1use std::fmt;
4use std::net::{Ipv4Addr, Ipv6Addr};
5
6use crate::oxm::{self, ct_state, OxmClass, OxmField};
7
8pub type MacAddr = [u8; 6];
10
11#[allow(dead_code)]
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14#[repr(u16)]
15pub enum MatchType {
16 Standard = 0,
18 Oxm = 1,
20}
21
22#[derive(Debug, Clone, Default)]
26pub struct Match {
27 pub in_port: Option<u32>,
29 pub in_phy_port: Option<u32>,
31 pub metadata: Option<u64>,
33 pub metadata_mask: Option<u64>,
35
36 pub eth_src: Option<MacAddr>,
39 pub eth_src_mask: Option<MacAddr>,
41 pub eth_dst: Option<MacAddr>,
43 pub eth_dst_mask: Option<MacAddr>,
45 pub eth_type: Option<u16>,
47 pub vlan_vid: Option<u16>,
49 pub vlan_pcp: Option<u8>,
51
52 pub ipv4_src: Option<Ipv4Addr>,
55 pub ipv4_src_mask: Option<u8>,
57 pub ipv4_dst: Option<Ipv4Addr>,
59 pub ipv4_dst_mask: Option<u8>,
61 pub ip_proto: Option<u8>,
63 pub ip_dscp: Option<u8>,
65 pub ip_ecn: Option<u8>,
67
68 pub ipv6_src: Option<Ipv6Addr>,
71 pub ipv6_src_mask: Option<u8>,
73 pub ipv6_dst: Option<Ipv6Addr>,
75 pub ipv6_dst_mask: Option<u8>,
77 pub ipv6_flabel: Option<u32>,
79
80 pub tcp_src: Option<u16>,
83 pub tcp_dst: Option<u16>,
85 pub tcp_flags: Option<u16>,
87
88 pub udp_src: Option<u16>,
91 pub udp_dst: Option<u16>,
93
94 pub icmp_type: Option<u8>,
97 pub icmp_code: Option<u8>,
99
100 pub icmpv6_type: Option<u8>,
103 pub icmpv6_code: Option<u8>,
105
106 pub arp_op: Option<u16>,
109 pub arp_spa: Option<Ipv4Addr>,
111 pub arp_tpa: Option<Ipv4Addr>,
113 pub arp_sha: Option<MacAddr>,
115 pub arp_tha: Option<MacAddr>,
117
118 pub tunnel_id: Option<u64>,
121
122 pub ct_state: Option<u32>,
125 pub ct_state_mask: Option<u32>,
127 pub ct_zone: Option<u16>,
129 pub ct_mark: Option<u32>,
131 pub ct_mark_mask: Option<u32>,
133}
134
135impl Match {
136 pub fn new() -> Self {
138 Self::default()
139 }
140
141 pub fn in_port(mut self, port: u32) -> Self {
143 self.in_port = Some(port);
144 self
145 }
146
147 pub fn eth_src(mut self, addr: MacAddr) -> Self {
149 self.eth_src = Some(addr);
150 self
151 }
152
153 pub fn eth_dst(mut self, addr: MacAddr) -> Self {
155 self.eth_dst = Some(addr);
156 self
157 }
158
159 pub fn eth_type(mut self, etype: u16) -> Self {
161 self.eth_type = Some(etype);
162 self
163 }
164
165 pub fn vlan_vid(mut self, vid: u16) -> Self {
167 self.vlan_vid = Some(vid);
168 self
169 }
170
171 pub fn ipv4_src(mut self, addr: Ipv4Addr, prefix_len: u8) -> Self {
173 self.eth_type = Some(0x0800); self.ipv4_src = Some(addr);
175 self.ipv4_src_mask = Some(prefix_len);
176 self
177 }
178
179 pub fn ipv4_dst(mut self, addr: Ipv4Addr, prefix_len: u8) -> Self {
181 self.eth_type = Some(0x0800); self.ipv4_dst = Some(addr);
183 self.ipv4_dst_mask = Some(prefix_len);
184 self
185 }
186
187 pub fn ipv6_src(mut self, addr: Ipv6Addr, prefix_len: u8) -> Self {
189 self.eth_type = Some(0x86dd); self.ipv6_src = Some(addr);
191 self.ipv6_src_mask = Some(prefix_len);
192 self
193 }
194
195 pub fn ipv6_dst(mut self, addr: Ipv6Addr, prefix_len: u8) -> Self {
197 self.eth_type = Some(0x86dd); self.ipv6_dst = Some(addr);
199 self.ipv6_dst_mask = Some(prefix_len);
200 self
201 }
202
203 pub fn ip_proto(mut self, proto: u8) -> Self {
205 self.ip_proto = Some(proto);
206 self
207 }
208
209 pub fn tcp_src(mut self, port: u16) -> Self {
211 self.ip_proto = Some(6); self.tcp_src = Some(port);
213 self
214 }
215
216 pub fn tcp_dst(mut self, port: u16) -> Self {
218 self.ip_proto = Some(6); self.tcp_dst = Some(port);
220 self
221 }
222
223 pub fn udp_src(mut self, port: u16) -> Self {
225 self.ip_proto = Some(17); self.udp_src = Some(port);
227 self
228 }
229
230 pub fn udp_dst(mut self, port: u16) -> Self {
232 self.ip_proto = Some(17); self.udp_dst = Some(port);
234 self
235 }
236
237 pub fn tunnel_id(mut self, id: u64) -> Self {
239 self.tunnel_id = Some(id);
240 self
241 }
242
243 pub fn ct_state(mut self, state: u32) -> Self {
261 self.ct_state = Some(state);
262 self.ct_state_mask = Some(state); self
264 }
265
266 pub fn ct_state_masked(mut self, state: u32, mask: u32) -> Self {
282 self.ct_state = Some(state);
283 self.ct_state_mask = Some(mask);
284 self
285 }
286
287 pub fn ct_zone(mut self, zone: u16) -> Self {
291 self.ct_zone = Some(zone);
292 self
293 }
294
295 pub fn ct_mark(mut self, mark: u32) -> Self {
300 self.ct_mark = Some(mark);
301 self
302 }
303
304 #[allow(clippy::similar_names)]
306 pub fn ct_mark_masked(mut self, mark: u32, mask: u32) -> Self {
307 self.ct_mark = Some(mark);
308 self.ct_mark_mask = Some(mask);
309 self
310 }
311
312 pub fn arp_op(mut self, opcode: u16) -> Self {
316 self.eth_type = Some(0x0806); self.arp_op = Some(opcode);
318 self
319 }
320
321 pub fn arp_spa(mut self, addr: impl Into<Ipv4Addr>) -> Self {
323 self.eth_type = Some(0x0806); self.arp_spa = Some(addr.into());
325 self
326 }
327
328 pub fn arp_tpa(mut self, addr: impl Into<Ipv4Addr>) -> Self {
330 self.eth_type = Some(0x0806); self.arp_tpa = Some(addr.into());
332 self
333 }
334
335 pub fn arp_sha(mut self, addr: MacAddr) -> Self {
337 self.eth_type = Some(0x0806); self.arp_sha = Some(addr);
339 self
340 }
341
342 pub fn arp_tha(mut self, addr: MacAddr) -> Self {
344 self.eth_type = Some(0x0806); self.arp_tha = Some(addr);
346 self
347 }
348
349 pub fn icmp_type(mut self, icmp_type: u8) -> Self {
353 self.eth_type = Some(0x0800); self.ip_proto = Some(1); self.icmp_type = Some(icmp_type);
356 self
357 }
358
359 pub fn icmp_code(mut self, code: u8) -> Self {
361 self.eth_type = Some(0x0800); self.ip_proto = Some(1); self.icmp_code = Some(code);
364 self
365 }
366
367 pub fn icmpv6_type(mut self, icmp_type: u8) -> Self {
373 self.eth_type = Some(0x86dd); self.ip_proto = Some(58); self.icmpv6_type = Some(icmp_type);
376 self
377 }
378
379 pub fn icmpv6_code(mut self, code: u8) -> Self {
381 self.eth_type = Some(0x86dd); self.ip_proto = Some(58); self.icmpv6_code = Some(code);
384 self
385 }
386
387 pub fn is_empty(&self) -> bool {
389 self.in_port.is_none()
390 && self.eth_src.is_none()
391 && self.eth_dst.is_none()
392 && self.eth_type.is_none()
393 && self.vlan_vid.is_none()
394 && self.ipv4_src.is_none()
395 && self.ipv4_dst.is_none()
396 && self.ip_proto.is_none()
397 && self.tcp_src.is_none()
398 && self.tcp_dst.is_none()
399 && self.udp_src.is_none()
400 && self.udp_dst.is_none()
401 && self.icmp_type.is_none()
402 && self.icmp_code.is_none()
403 && self.icmpv6_type.is_none()
404 && self.icmpv6_code.is_none()
405 && self.tunnel_id.is_none()
406 && self.arp_op.is_none()
407 && self.arp_spa.is_none()
408 && self.arp_tpa.is_none()
409 && self.arp_sha.is_none()
410 && self.arp_tha.is_none()
411 && self.ct_state.is_none()
412 && self.ct_zone.is_none()
413 && self.ct_mark.is_none()
414 }
415}
416
417fn format_mac(mac: MacAddr) -> String {
419 format!(
420 "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
421 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
422 )
423}
424
425fn format_ct_state(state: u32) -> String {
427 let mut parts = Vec::new();
428 if state & ct_state::TRK != 0 { parts.push("+trk"); }
429 if state & ct_state::NEW != 0 { parts.push("+new"); }
430 if state & ct_state::EST != 0 { parts.push("+est"); }
431 if state & ct_state::REL != 0 { parts.push("+rel"); }
432 if state & ct_state::RPL != 0 { parts.push("+rpl"); }
433 if state & ct_state::INV != 0 { parts.push("+inv"); }
434 if state & ct_state::SNAT != 0 { parts.push("+snat"); }
435 if state & ct_state::DNAT != 0 { parts.push("+dnat"); }
436 if parts.is_empty() {
437 format!("0x{state:x}")
438 } else {
439 parts.join("")
440 }
441}
442
443impl fmt::Display for Match {
444 #[allow(clippy::too_many_lines)]
445 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
446 if self.is_empty() {
447 return write!(f, "*");
448 }
449
450 let mut parts: Vec<String> = Vec::new();
451
452 if let Some(p) = self.in_port {
453 parts.push(format!("in_port={p}"));
454 }
455 if let Some(p) = self.in_phy_port {
456 parts.push(format!("in_phy_port={p}"));
457 }
458 if let Some(m) = self.metadata {
459 if let Some(mask) = self.metadata_mask {
460 if mask == u64::MAX {
461 parts.push(format!("metadata=0x{m:x}"));
462 } else {
463 parts.push(format!("metadata=0x{m:x}/0x{mask:x}"));
464 }
465 } else {
466 parts.push(format!("metadata=0x{m:x}"));
467 }
468 }
469 if let Some(mac) = self.eth_src {
470 let s = format_mac(mac);
471 if let Some(mask) = self.eth_src_mask {
472 if mask == [0xff; 6] {
473 parts.push(format!("eth_src={s}"));
474 } else {
475 parts.push(format!("eth_src={s}/{}", format_mac(mask)));
476 }
477 } else {
478 parts.push(format!("eth_src={s}"));
479 }
480 }
481 if let Some(mac) = self.eth_dst {
482 let s = format_mac(mac);
483 if let Some(mask) = self.eth_dst_mask {
484 if mask == [0xff; 6] {
485 parts.push(format!("eth_dst={s}"));
486 } else {
487 parts.push(format!("eth_dst={s}/{}", format_mac(mask)));
488 }
489 } else {
490 parts.push(format!("eth_dst={s}"));
491 }
492 }
493 if let Some(et) = self.eth_type {
494 parts.push(format!("eth_type=0x{et:04x}"));
495 }
496 if let Some(vid) = self.vlan_vid {
497 parts.push(format!("vlan_vid={vid}"));
498 }
499 if let Some(pcp) = self.vlan_pcp {
500 parts.push(format!("vlan_pcp={pcp}"));
501 }
502 if let Some(proto) = self.ip_proto {
503 parts.push(format!("ip_proto={proto}"));
504 }
505 if let Some(dscp) = self.ip_dscp {
506 parts.push(format!("ip_dscp={dscp}"));
507 }
508 if let Some(ecn) = self.ip_ecn {
509 parts.push(format!("ip_ecn={ecn}"));
510 }
511 if let Some(ip) = self.ipv4_src {
512 let prefix = self.ipv4_src_mask.unwrap_or(32);
513 if prefix < 32 {
514 parts.push(format!("ipv4_src={ip}/{prefix}"));
515 } else {
516 parts.push(format!("ipv4_src={ip}"));
517 }
518 }
519 if let Some(ip) = self.ipv4_dst {
520 let prefix = self.ipv4_dst_mask.unwrap_or(32);
521 if prefix < 32 {
522 parts.push(format!("ipv4_dst={ip}/{prefix}"));
523 } else {
524 parts.push(format!("ipv4_dst={ip}"));
525 }
526 }
527 if let Some(ip) = self.ipv6_src {
528 let prefix = self.ipv6_src_mask.unwrap_or(128);
529 if prefix < 128 {
530 parts.push(format!("ipv6_src={ip}/{prefix}"));
531 } else {
532 parts.push(format!("ipv6_src={ip}"));
533 }
534 }
535 if let Some(ip) = self.ipv6_dst {
536 let prefix = self.ipv6_dst_mask.unwrap_or(128);
537 if prefix < 128 {
538 parts.push(format!("ipv6_dst={ip}/{prefix}"));
539 } else {
540 parts.push(format!("ipv6_dst={ip}"));
541 }
542 }
543 if let Some(fl) = self.ipv6_flabel {
544 parts.push(format!("ipv6_flabel=0x{fl:x}"));
545 }
546 if let Some(p) = self.tcp_src {
547 parts.push(format!("tcp_src={p}"));
548 }
549 if let Some(p) = self.tcp_dst {
550 parts.push(format!("tcp_dst={p}"));
551 }
552 if let Some(flags) = self.tcp_flags {
553 parts.push(format!("tcp_flags=0x{flags:x}"));
554 }
555 if let Some(p) = self.udp_src {
556 parts.push(format!("udp_src={p}"));
557 }
558 if let Some(p) = self.udp_dst {
559 parts.push(format!("udp_dst={p}"));
560 }
561 if let Some(t) = self.icmp_type {
562 parts.push(format!("icmp_type={t}"));
563 }
564 if let Some(c) = self.icmp_code {
565 parts.push(format!("icmp_code={c}"));
566 }
567 if let Some(t) = self.icmpv6_type {
568 parts.push(format!("icmpv6_type={t}"));
569 }
570 if let Some(c) = self.icmpv6_code {
571 parts.push(format!("icmpv6_code={c}"));
572 }
573 if let Some(op) = self.arp_op {
574 parts.push(format!("arp_op={op}"));
575 }
576 if let Some(ip) = self.arp_spa {
577 parts.push(format!("arp_spa={ip}"));
578 }
579 if let Some(ip) = self.arp_tpa {
580 parts.push(format!("arp_tpa={ip}"));
581 }
582 if let Some(mac) = self.arp_sha {
583 parts.push(format!("arp_sha={}", format_mac(mac)));
584 }
585 if let Some(mac) = self.arp_tha {
586 parts.push(format!("arp_tha={}", format_mac(mac)));
587 }
588 if let Some(id) = self.tunnel_id {
589 parts.push(format!("tunnel_id={id:#x}"));
590 }
591 if let Some(state) = self.ct_state {
592 let s = format_ct_state(state);
593 if let Some(mask) = self.ct_state_mask {
594 if mask == state {
595 parts.push(format!("ct_state={s}"));
596 } else {
597 parts.push(format!("ct_state={s}/{}", format_ct_state(mask)));
598 }
599 } else {
600 parts.push(format!("ct_state={s}"));
601 }
602 }
603 if let Some(z) = self.ct_zone {
604 parts.push(format!("ct_zone={z}"));
605 }
606 if let Some(mark) = self.ct_mark {
607 if let Some(mask) = self.ct_mark_mask {
608 if mask == u32::MAX {
609 parts.push(format!("ct_mark=0x{mark:x}"));
610 } else {
611 parts.push(format!("ct_mark=0x{mark:x}/0x{mask:x}"));
612 }
613 } else {
614 parts.push(format!("ct_mark=0x{mark:x}"));
615 }
616 }
617
618 write!(f, "{}", parts.join(","))
619 }
620}
621
622impl Match {
623 pub fn decode_oxm(oxm_data: &[u8]) -> crate::Result<Self> {
628 let mut m = Match::new();
629 let mut offset = 0;
630
631 while offset + 4 <= oxm_data.len() {
632 let header = u32::from_be_bytes([
633 oxm_data[offset],
634 oxm_data[offset + 1],
635 oxm_data[offset + 2],
636 oxm_data[offset + 3],
637 ]);
638
639 let oxm_class = (header >> 16) as u16;
640 let field = ((header >> 9) & 0x7f) as u8;
641 let has_mask = ((header >> 8) & 1) != 0;
642 let length = (header & 0xff) as usize;
643
644 offset += 4; if offset + length > oxm_data.len() {
647 break; }
649
650 let value = &oxm_data[offset..offset + length];
651 let value_len = if has_mask { length / 2 } else { length };
652
653 if oxm_class == OxmClass::OpenflowBasic as u16 {
655 Self::decode_oxm_field(&mut m, field, has_mask, value, value_len);
656 } else if oxm_class == OxmClass::Nxm1 as u16 {
657 Self::decode_nxm_field(&mut m, field, has_mask, value, value_len);
658 } else if oxm_class == OxmClass::Nxm0 as u16 {
659 Self::decode_nxm0_field(&mut m, field, has_mask, value, value_len);
660 }
661 offset += length;
664 }
665
666 Ok(m)
667 }
668
669 #[allow(clippy::too_many_lines)]
674 pub fn decode(data: &[u8]) -> crate::Result<(Self, usize)> {
675 if data.len() < 4 {
676 return Err(crate::Error::Parse("match header too short".into()));
677 }
678
679 let match_type = u16::from_be_bytes([data[0], data[1]]);
680 let match_len = u16::from_be_bytes([data[2], data[3]]) as usize;
681
682 if match_type != MatchType::Oxm as u16 {
683 return Err(crate::Error::Parse(format!(
684 "unsupported match type: {match_type}"
685 )));
686 }
687
688 if data.len() < match_len {
689 return Err(crate::Error::Parse("match data truncated".into()));
690 }
691
692 let mut m = Match::new();
693 let oxm_data = &data[4..match_len];
694 let mut offset = 0;
695
696 while offset + 4 <= oxm_data.len() {
697 let header = u32::from_be_bytes([
698 oxm_data[offset],
699 oxm_data[offset + 1],
700 oxm_data[offset + 2],
701 oxm_data[offset + 3],
702 ]);
703
704 let oxm_class = (header >> 16) as u16;
705 let field = ((header >> 9) & 0x7f) as u8;
706 let has_mask = ((header >> 8) & 1) != 0;
707 let length = (header & 0xff) as usize;
708
709 offset += 4; if offset + length > oxm_data.len() {
712 break; }
714
715 let value = &oxm_data[offset..offset + length];
716 let value_len = if has_mask { length / 2 } else { length };
717
718 if oxm_class == OxmClass::OpenflowBasic as u16 {
720 Self::decode_oxm_field(&mut m, field, has_mask, value, value_len);
721 } else if oxm_class == OxmClass::Nxm1 as u16 {
722 Self::decode_nxm_field(&mut m, field, has_mask, value, value_len);
723 } else if oxm_class == OxmClass::Nxm0 as u16 {
724 Self::decode_nxm0_field(&mut m, field, has_mask, value, value_len);
725 }
726 offset += length;
729 }
730
731 let padded_len = (match_len + 7) & !7;
733
734 Ok((m, padded_len))
735 }
736
737 #[allow(clippy::too_many_lines)]
739 fn decode_oxm_field(
740 m: &mut Match,
741 field: u8,
742 has_mask: bool,
743 value: &[u8],
744 value_len: usize,
745 ) {
746 match field {
747 f if f == OxmField::InPort as u8 => {
748 if value_len >= 4 {
749 m.in_port = Some(u32::from_be_bytes([value[0], value[1], value[2], value[3]]));
750 }
751 }
752 f if f == OxmField::InPhyPort as u8 => {
753 if value_len >= 4 {
754 m.in_phy_port = Some(u32::from_be_bytes([value[0], value[1], value[2], value[3]]));
755 }
756 }
757 f if f == OxmField::Metadata as u8 => {
758 if value_len >= 8 {
759 m.metadata = Some(u64::from_be_bytes([
760 value[0], value[1], value[2], value[3],
761 value[4], value[5], value[6], value[7],
762 ]));
763 if has_mask && value.len() >= 16 {
764 m.metadata_mask = Some(u64::from_be_bytes([
765 value[8], value[9], value[10], value[11],
766 value[12], value[13], value[14], value[15],
767 ]));
768 }
769 }
770 }
771 f if f == OxmField::EthDst as u8 => {
772 if value_len >= 6 {
773 let mut mac = [0u8; 6];
774 mac.copy_from_slice(&value[..6]);
775 m.eth_dst = Some(mac);
776 if has_mask && value.len() >= 12 {
777 let mut mask = [0u8; 6];
778 mask.copy_from_slice(&value[6..12]);
779 m.eth_dst_mask = Some(mask);
780 }
781 }
782 }
783 f if f == OxmField::EthSrc as u8 => {
784 if value_len >= 6 {
785 let mut mac = [0u8; 6];
786 mac.copy_from_slice(&value[..6]);
787 m.eth_src = Some(mac);
788 if has_mask && value.len() >= 12 {
789 let mut mask = [0u8; 6];
790 mask.copy_from_slice(&value[6..12]);
791 m.eth_src_mask = Some(mask);
792 }
793 }
794 }
795 f if f == OxmField::EthType as u8 => {
796 if value_len >= 2 {
797 m.eth_type = Some(u16::from_be_bytes([value[0], value[1]]));
798 }
799 }
800 f if f == OxmField::VlanVid as u8 => {
801 if value_len >= 2 {
802 let vid = u16::from_be_bytes([value[0], value[1]]);
803 m.vlan_vid = Some(vid & 0x0fff);
805 }
806 }
807 f if f == OxmField::VlanPcp as u8 => {
808 if value_len >= 1 {
809 m.vlan_pcp = Some(value[0]);
810 }
811 }
812 f if f == OxmField::IpDscp as u8 => {
813 if value_len >= 1 {
814 m.ip_dscp = Some(value[0]);
815 }
816 }
817 f if f == OxmField::IpEcn as u8 => {
818 if value_len >= 1 {
819 m.ip_ecn = Some(value[0]);
820 }
821 }
822 f if f == OxmField::IpProto as u8 => {
823 if value_len >= 1 {
824 m.ip_proto = Some(value[0]);
825 }
826 }
827 f if f == OxmField::Ipv4Src as u8 => {
828 if value_len >= 4 {
829 let addr = Ipv4Addr::new(value[0], value[1], value[2], value[3]);
830 m.ipv4_src = Some(addr);
831 if has_mask && value.len() >= 8 {
832 let mask = u32::from_be_bytes([value[4], value[5], value[6], value[7]]);
833 m.ipv4_src_mask = Some(mask_to_prefix(mask));
834 } else {
835 m.ipv4_src_mask = Some(32);
836 }
837 }
838 }
839 f if f == OxmField::Ipv4Dst as u8 => {
840 if value_len >= 4 {
841 let addr = Ipv4Addr::new(value[0], value[1], value[2], value[3]);
842 m.ipv4_dst = Some(addr);
843 if has_mask && value.len() >= 8 {
844 let mask = u32::from_be_bytes([value[4], value[5], value[6], value[7]]);
845 m.ipv4_dst_mask = Some(mask_to_prefix(mask));
846 } else {
847 m.ipv4_dst_mask = Some(32);
848 }
849 }
850 }
851 f if f == OxmField::TcpSrc as u8 => {
852 if value_len >= 2 {
853 m.tcp_src = Some(u16::from_be_bytes([value[0], value[1]]));
854 }
855 }
856 f if f == OxmField::TcpDst as u8 => {
857 if value_len >= 2 {
858 m.tcp_dst = Some(u16::from_be_bytes([value[0], value[1]]));
859 }
860 }
861 f if f == OxmField::UdpSrc as u8 => {
862 if value_len >= 2 {
863 m.udp_src = Some(u16::from_be_bytes([value[0], value[1]]));
864 }
865 }
866 f if f == OxmField::UdpDst as u8 => {
867 if value_len >= 2 {
868 m.udp_dst = Some(u16::from_be_bytes([value[0], value[1]]));
869 }
870 }
871 f if f == OxmField::Icmpv4Type as u8 => {
872 if value_len >= 1 {
873 m.icmp_type = Some(value[0]);
874 }
875 }
876 f if f == OxmField::Icmpv4Code as u8 => {
877 if value_len >= 1 {
878 m.icmp_code = Some(value[0]);
879 }
880 }
881 f if f == OxmField::Icmpv6Type as u8 => {
882 if value_len >= 1 {
883 m.icmpv6_type = Some(value[0]);
884 }
885 }
886 f if f == OxmField::Icmpv6Code as u8 => {
887 if value_len >= 1 {
888 m.icmpv6_code = Some(value[0]);
889 }
890 }
891 f if f == OxmField::ArpOp as u8 => {
892 if value_len >= 2 {
893 m.arp_op = Some(u16::from_be_bytes([value[0], value[1]]));
894 }
895 }
896 f if f == OxmField::ArpSpa as u8 => {
897 if value_len >= 4 {
898 m.arp_spa = Some(Ipv4Addr::new(value[0], value[1], value[2], value[3]));
899 }
900 }
901 f if f == OxmField::ArpTpa as u8 => {
902 if value_len >= 4 {
903 m.arp_tpa = Some(Ipv4Addr::new(value[0], value[1], value[2], value[3]));
904 }
905 }
906 f if f == OxmField::ArpSha as u8 => {
907 if value_len >= 6 {
908 let mut mac = [0u8; 6];
909 mac.copy_from_slice(&value[..6]);
910 m.arp_sha = Some(mac);
911 }
912 }
913 f if f == OxmField::ArpTha as u8 => {
914 if value_len >= 6 {
915 let mut mac = [0u8; 6];
916 mac.copy_from_slice(&value[..6]);
917 m.arp_tha = Some(mac);
918 }
919 }
920 f if f == OxmField::Ipv6Src as u8 => {
921 if value_len >= 16 {
922 let mut octets = [0u8; 16];
923 octets.copy_from_slice(&value[..16]);
924 m.ipv6_src = Some(Ipv6Addr::from(octets));
925 if has_mask && value.len() >= 32 {
926 let mut mask_bytes = [0u8; 16];
927 mask_bytes.copy_from_slice(&value[16..32]);
928 let mask = u128::from_be_bytes(mask_bytes);
929 m.ipv6_src_mask = Some(mask_to_prefix_v6(mask));
930 } else {
931 m.ipv6_src_mask = Some(128);
932 }
933 }
934 }
935 f if f == OxmField::Ipv6Dst as u8 => {
936 if value_len >= 16 {
937 let mut octets = [0u8; 16];
938 octets.copy_from_slice(&value[..16]);
939 m.ipv6_dst = Some(Ipv6Addr::from(octets));
940 if has_mask && value.len() >= 32 {
941 let mut mask_bytes = [0u8; 16];
942 mask_bytes.copy_from_slice(&value[16..32]);
943 let mask = u128::from_be_bytes(mask_bytes);
944 m.ipv6_dst_mask = Some(mask_to_prefix_v6(mask));
945 } else {
946 m.ipv6_dst_mask = Some(128);
947 }
948 }
949 }
950 f if f == OxmField::Ipv6Flabel as u8 => {
951 if value_len >= 4 {
952 m.ipv6_flabel = Some(u32::from_be_bytes([value[0], value[1], value[2], value[3]]));
953 }
954 }
955 f if f == OxmField::TunnelId as u8 => {
956 if value_len >= 8 {
957 m.tunnel_id = Some(u64::from_be_bytes([
958 value[0], value[1], value[2], value[3],
959 value[4], value[5], value[6], value[7],
960 ]));
961 }
962 }
963 _ => {
964 }
966 }
967 }
968
969 fn decode_nxm0_field(
978 m: &mut Match,
979 field: u8,
980 has_mask: bool,
981 value: &[u8],
982 value_len: usize,
983 ) {
984 match field {
985 0 if value_len >= 2 => {
987 m.in_port = Some(u16::from_be_bytes([value[0], value[1]]) as u32);
988 }
989 1 if value_len >= 6 => {
991 let mut mac = [0u8; 6];
992 mac.copy_from_slice(&value[..6]);
993 m.eth_dst = Some(mac);
994 if has_mask && value.len() >= 12 {
995 let mut mask = [0u8; 6];
996 mask.copy_from_slice(&value[6..12]);
997 m.eth_dst_mask = Some(mask);
998 }
999 }
1000 2 if value_len >= 6 => {
1002 let mut mac = [0u8; 6];
1003 mac.copy_from_slice(&value[..6]);
1004 m.eth_src = Some(mac);
1005 if has_mask && value.len() >= 12 {
1006 let mut mask = [0u8; 6];
1007 mask.copy_from_slice(&value[6..12]);
1008 m.eth_src_mask = Some(mask);
1009 }
1010 }
1011 3 if value_len >= 2 => {
1013 m.eth_type = Some(u16::from_be_bytes([value[0], value[1]]));
1014 }
1015 4 if value_len >= 2 => {
1017 let tci = u16::from_be_bytes([value[0], value[1]]);
1018 m.vlan_vid = Some(tci);
1020 }
1021 5 if value_len >= 1 => {
1023 m.ip_dscp = Some(value[0] >> 2);
1024 }
1025 6 if value_len >= 1 => {
1027 m.ip_proto = Some(value[0]);
1028 }
1029 7 if value_len >= 4 => {
1031 m.ipv4_src = Some(Ipv4Addr::new(value[0], value[1], value[2], value[3]));
1032 if has_mask && value.len() >= 8 {
1033 let mask = u32::from_be_bytes([value[4], value[5], value[6], value[7]]);
1034 m.ipv4_src_mask = Some(mask_to_prefix(mask));
1035 } else {
1036 m.ipv4_src_mask = Some(32);
1037 }
1038 }
1039 8 if value_len >= 4 => {
1041 m.ipv4_dst = Some(Ipv4Addr::new(value[0], value[1], value[2], value[3]));
1042 if has_mask && value.len() >= 8 {
1043 let mask = u32::from_be_bytes([value[4], value[5], value[6], value[7]]);
1044 m.ipv4_dst_mask = Some(mask_to_prefix(mask));
1045 } else {
1046 m.ipv4_dst_mask = Some(32);
1047 }
1048 }
1049 9 if value_len >= 2 => {
1051 m.tcp_src = Some(u16::from_be_bytes([value[0], value[1]]));
1052 }
1053 10 if value_len >= 2 => {
1055 m.tcp_dst = Some(u16::from_be_bytes([value[0], value[1]]));
1056 }
1057 11 if value_len >= 2 => {
1059 m.udp_src = Some(u16::from_be_bytes([value[0], value[1]]));
1060 }
1061 12 if value_len >= 2 => {
1063 m.udp_dst = Some(u16::from_be_bytes([value[0], value[1]]));
1064 }
1065 13 if value_len >= 1 => {
1067 m.icmp_type = Some(value[0]);
1068 }
1069 14 if value_len >= 1 => {
1071 m.icmp_code = Some(value[0]);
1072 }
1073 15 if value_len >= 2 => {
1075 m.arp_op = Some(u16::from_be_bytes([value[0], value[1]]));
1076 }
1077 16 if value_len >= 4 => {
1079 m.arp_spa = Some(Ipv4Addr::new(value[0], value[1], value[2], value[3]));
1080 }
1081 17 if value_len >= 4 => {
1083 m.arp_tpa = Some(Ipv4Addr::new(value[0], value[1], value[2], value[3]));
1084 }
1085 _ => {
1086 }
1088 }
1089 }
1090
1091 fn decode_nxm_field(
1092 m: &mut Match,
1093 field: u8,
1094 has_mask: bool,
1095 value: &[u8],
1096 value_len: usize,
1097 ) {
1098 match field {
1099 16 if value_len >= 8 => {
1101 m.tunnel_id = Some(u64::from_be_bytes([
1102 value[0], value[1], value[2], value[3],
1103 value[4], value[5], value[6], value[7],
1104 ]));
1105 }
1106 105 if value_len >= 4 => {
1108 m.ct_state = Some(u32::from_be_bytes([
1109 value[0], value[1], value[2], value[3],
1110 ]));
1111 if has_mask && value.len() >= 8 {
1112 m.ct_state_mask = Some(u32::from_be_bytes([
1113 value[4], value[5], value[6], value[7],
1114 ]));
1115 }
1116 }
1117 106 if value_len >= 2 => {
1119 m.ct_zone = Some(u16::from_be_bytes([value[0], value[1]]));
1120 }
1121 107 if value_len >= 4 => {
1123 m.ct_mark = Some(u32::from_be_bytes([
1124 value[0], value[1], value[2], value[3],
1125 ]));
1126 if has_mask && value.len() >= 8 {
1127 m.ct_mark_mask = Some(u32::from_be_bytes([
1128 value[4], value[5], value[6], value[7],
1129 ]));
1130 }
1131 }
1132 _ => {
1133 }
1135 }
1136 }
1137
1138 #[allow(clippy::too_many_lines)]
1148 pub fn encode(&self) -> Vec<u8> {
1149 let mut oxm_fields = Vec::new();
1151
1152 if let Some(port) = self.in_port {
1157 oxm_fields.extend(oxm::encode_u32(
1158 OxmClass::OpenflowBasic,
1159 OxmField::InPort as u8,
1160 port,
1161 ));
1162 }
1163 if let Some(port) = self.in_phy_port {
1164 oxm_fields.extend(oxm::encode_u32(
1165 OxmClass::OpenflowBasic,
1166 OxmField::InPhyPort as u8,
1167 port,
1168 ));
1169 }
1170
1171 if let Some(metadata) = self.metadata {
1173 if let Some(mask) = self.metadata_mask {
1174 oxm_fields.extend(oxm::encode_u64_masked(
1175 OxmClass::OpenflowBasic,
1176 OxmField::Metadata as u8,
1177 metadata,
1178 mask,
1179 ));
1180 } else {
1181 oxm_fields.extend(oxm::encode_u64(
1182 OxmClass::OpenflowBasic,
1183 OxmField::Metadata as u8,
1184 metadata,
1185 ));
1186 }
1187 }
1188
1189 if let Some(mac) = self.eth_dst {
1191 if let Some(mask) = self.eth_dst_mask {
1192 oxm_fields.extend(oxm::encode_mac_masked(
1193 OxmClass::OpenflowBasic,
1194 OxmField::EthDst as u8,
1195 mac,
1196 mask,
1197 ));
1198 } else {
1199 oxm_fields.extend(oxm::encode_mac(
1200 OxmClass::OpenflowBasic,
1201 OxmField::EthDst as u8,
1202 mac,
1203 ));
1204 }
1205 }
1206 if let Some(mac) = self.eth_src {
1207 if let Some(mask) = self.eth_src_mask {
1208 oxm_fields.extend(oxm::encode_mac_masked(
1209 OxmClass::OpenflowBasic,
1210 OxmField::EthSrc as u8,
1211 mac,
1212 mask,
1213 ));
1214 } else {
1215 oxm_fields.extend(oxm::encode_mac(
1216 OxmClass::OpenflowBasic,
1217 OxmField::EthSrc as u8,
1218 mac,
1219 ));
1220 }
1221 }
1222 if let Some(eth_type) = self.eth_type {
1223 oxm_fields.extend(oxm::encode_u16(
1224 OxmClass::OpenflowBasic,
1225 OxmField::EthType as u8,
1226 eth_type,
1227 ));
1228 }
1229 if let Some(vid) = self.vlan_vid {
1230 oxm_fields.extend(oxm::encode_u16(
1232 OxmClass::OpenflowBasic,
1233 OxmField::VlanVid as u8,
1234 vid | 0x1000,
1235 ));
1236 }
1237 if let Some(pcp) = self.vlan_pcp {
1238 oxm_fields.extend(oxm::encode_u8(
1239 OxmClass::OpenflowBasic,
1240 OxmField::VlanPcp as u8,
1241 pcp,
1242 ));
1243 }
1244
1245 if let Some(dscp) = self.ip_dscp {
1247 oxm_fields.extend(oxm::encode_u8(
1248 OxmClass::OpenflowBasic,
1249 OxmField::IpDscp as u8,
1250 dscp,
1251 ));
1252 }
1253 if let Some(ecn) = self.ip_ecn {
1254 oxm_fields.extend(oxm::encode_u8(
1255 OxmClass::OpenflowBasic,
1256 OxmField::IpEcn as u8,
1257 ecn,
1258 ));
1259 }
1260 if let Some(proto) = self.ip_proto {
1261 oxm_fields.extend(oxm::encode_u8(
1262 OxmClass::OpenflowBasic,
1263 OxmField::IpProto as u8,
1264 proto,
1265 ));
1266 }
1267 if let Some(addr) = self.ipv4_src {
1268 let addr_u32: u32 = addr.into();
1269 if let Some(prefix) = self.ipv4_src_mask {
1270 if prefix < 32 {
1271 let mask = oxm::prefix_to_mask(prefix);
1272 oxm_fields.extend(oxm::encode_u32_masked(
1273 OxmClass::OpenflowBasic,
1274 OxmField::Ipv4Src as u8,
1275 addr_u32,
1276 mask,
1277 ));
1278 } else {
1279 oxm_fields.extend(oxm::encode_u32(
1280 OxmClass::OpenflowBasic,
1281 OxmField::Ipv4Src as u8,
1282 addr_u32,
1283 ));
1284 }
1285 } else {
1286 oxm_fields.extend(oxm::encode_u32(
1287 OxmClass::OpenflowBasic,
1288 OxmField::Ipv4Src as u8,
1289 addr_u32,
1290 ));
1291 }
1292 }
1293 if let Some(addr) = self.ipv4_dst {
1294 let addr_u32: u32 = addr.into();
1295 if let Some(prefix) = self.ipv4_dst_mask {
1296 if prefix < 32 {
1297 let mask = oxm::prefix_to_mask(prefix);
1298 oxm_fields.extend(oxm::encode_u32_masked(
1299 OxmClass::OpenflowBasic,
1300 OxmField::Ipv4Dst as u8,
1301 addr_u32,
1302 mask,
1303 ));
1304 } else {
1305 oxm_fields.extend(oxm::encode_u32(
1306 OxmClass::OpenflowBasic,
1307 OxmField::Ipv4Dst as u8,
1308 addr_u32,
1309 ));
1310 }
1311 } else {
1312 oxm_fields.extend(oxm::encode_u32(
1313 OxmClass::OpenflowBasic,
1314 OxmField::Ipv4Dst as u8,
1315 addr_u32,
1316 ));
1317 }
1318 }
1319
1320 if let Some(port) = self.tcp_src {
1322 oxm_fields.extend(oxm::encode_u16(
1323 OxmClass::OpenflowBasic,
1324 OxmField::TcpSrc as u8,
1325 port,
1326 ));
1327 }
1328 if let Some(port) = self.tcp_dst {
1329 oxm_fields.extend(oxm::encode_u16(
1330 OxmClass::OpenflowBasic,
1331 OxmField::TcpDst as u8,
1332 port,
1333 ));
1334 }
1335
1336 if let Some(port) = self.udp_src {
1338 oxm_fields.extend(oxm::encode_u16(
1339 OxmClass::OpenflowBasic,
1340 OxmField::UdpSrc as u8,
1341 port,
1342 ));
1343 }
1344 if let Some(port) = self.udp_dst {
1345 oxm_fields.extend(oxm::encode_u16(
1346 OxmClass::OpenflowBasic,
1347 OxmField::UdpDst as u8,
1348 port,
1349 ));
1350 }
1351
1352 if let Some(icmp_type) = self.icmp_type {
1354 oxm_fields.extend(oxm::encode_u8(
1355 OxmClass::OpenflowBasic,
1356 OxmField::Icmpv4Type as u8,
1357 icmp_type,
1358 ));
1359 }
1360 if let Some(icmp_code) = self.icmp_code {
1361 oxm_fields.extend(oxm::encode_u8(
1362 OxmClass::OpenflowBasic,
1363 OxmField::Icmpv4Code as u8,
1364 icmp_code,
1365 ));
1366 }
1367
1368 if let Some(icmpv6_type) = self.icmpv6_type {
1370 oxm_fields.extend(oxm::encode_u8(
1371 OxmClass::OpenflowBasic,
1372 OxmField::Icmpv6Type as u8,
1373 icmpv6_type,
1374 ));
1375 }
1376 if let Some(icmpv6_code) = self.icmpv6_code {
1377 oxm_fields.extend(oxm::encode_u8(
1378 OxmClass::OpenflowBasic,
1379 OxmField::Icmpv6Code as u8,
1380 icmpv6_code,
1381 ));
1382 }
1383
1384 if let Some(op) = self.arp_op {
1386 oxm_fields.extend(oxm::encode_u16(
1387 OxmClass::OpenflowBasic,
1388 OxmField::ArpOp as u8,
1389 op,
1390 ));
1391 }
1392 if let Some(addr) = self.arp_spa {
1393 oxm_fields.extend(oxm::encode_u32(
1394 OxmClass::OpenflowBasic,
1395 OxmField::ArpSpa as u8,
1396 addr.into(),
1397 ));
1398 }
1399 if let Some(addr) = self.arp_tpa {
1400 oxm_fields.extend(oxm::encode_u32(
1401 OxmClass::OpenflowBasic,
1402 OxmField::ArpTpa as u8,
1403 addr.into(),
1404 ));
1405 }
1406 if let Some(mac) = self.arp_sha {
1407 oxm_fields.extend(oxm::encode_mac(
1408 OxmClass::OpenflowBasic,
1409 OxmField::ArpSha as u8,
1410 mac,
1411 ));
1412 }
1413 if let Some(mac) = self.arp_tha {
1414 oxm_fields.extend(oxm::encode_mac(
1415 OxmClass::OpenflowBasic,
1416 OxmField::ArpTha as u8,
1417 mac,
1418 ));
1419 }
1420
1421 if let Some(addr) = self.ipv6_src {
1423 let octets = addr.octets();
1424 let value = u128::from_be_bytes(octets);
1425 if let Some(prefix) = self.ipv6_src_mask {
1426 if prefix < 128 {
1427 let mask = oxm::prefix_to_mask_v6(prefix);
1428 oxm_fields.extend(encode_ipv6_masked(OxmField::Ipv6Src as u8, value, mask));
1429 } else {
1430 oxm_fields.extend(encode_ipv6(OxmField::Ipv6Src as u8, value));
1431 }
1432 } else {
1433 oxm_fields.extend(encode_ipv6(OxmField::Ipv6Src as u8, value));
1434 }
1435 }
1436 if let Some(addr) = self.ipv6_dst {
1437 let octets = addr.octets();
1438 let value = u128::from_be_bytes(octets);
1439 if let Some(prefix) = self.ipv6_dst_mask {
1440 if prefix < 128 {
1441 let mask = oxm::prefix_to_mask_v6(prefix);
1442 oxm_fields.extend(encode_ipv6_masked(OxmField::Ipv6Dst as u8, value, mask));
1443 } else {
1444 oxm_fields.extend(encode_ipv6(OxmField::Ipv6Dst as u8, value));
1445 }
1446 } else {
1447 oxm_fields.extend(encode_ipv6(OxmField::Ipv6Dst as u8, value));
1448 }
1449 }
1450 if let Some(flabel) = self.ipv6_flabel {
1451 oxm_fields.extend(oxm::encode_u32(
1452 OxmClass::OpenflowBasic,
1453 OxmField::Ipv6Flabel as u8,
1454 flabel,
1455 ));
1456 }
1457
1458 if let Some(tun_id) = self.tunnel_id {
1460 oxm_fields.extend(oxm::encode_tun_id(tun_id));
1461 }
1462
1463 if let Some(state) = self.ct_state {
1465 if let Some(mask) = self.ct_state_mask {
1466 if mask == 0xffff_ffff {
1467 oxm_fields.extend(oxm::encode_ct_state(state));
1468 } else {
1469 oxm_fields.extend(oxm::encode_ct_state_masked(state, mask));
1470 }
1471 } else {
1472 oxm_fields.extend(oxm::encode_ct_state(state));
1473 }
1474 }
1475 if let Some(zone) = self.ct_zone {
1476 oxm_fields.extend(oxm::encode_ct_zone(zone));
1477 }
1478 if let Some(mark) = self.ct_mark {
1479 if let Some(mask) = self.ct_mark_mask {
1480 oxm_fields.extend(oxm::encode_ct_mark_masked(mark, mask));
1481 } else {
1482 oxm_fields.extend(oxm::encode_ct_mark(mark));
1483 }
1484 }
1485
1486 let oxm_len = oxm_fields.len();
1490 let match_len = 4 + oxm_len; let padded_len = (match_len + 7) & !7; let padding = padded_len - match_len;
1493
1494 let mut buf = Vec::with_capacity(padded_len);
1495 buf.extend((MatchType::Oxm as u16).to_be_bytes()); buf.extend((match_len as u16).to_be_bytes()); buf.extend(oxm_fields);
1498 buf.extend(std::iter::repeat_n(0u8, padding));
1499 buf
1500 }
1501
1502 pub fn encode_oxm_fields(&self) -> Vec<u8> {
1507 let full = self.encode();
1509 if full.len() <= 4 {
1510 return Vec::new();
1511 }
1512 let match_len = u16::from_be_bytes([full[2], full[3]]) as usize;
1513 full[4..match_len].to_vec()
1515 }
1516}
1517
1518fn mask_to_prefix(mask: u32) -> u8 {
1520 mask.leading_ones() as u8
1521}
1522
1523fn mask_to_prefix_v6(mask: u128) -> u8 {
1525 mask.leading_ones() as u8
1526}
1527
1528fn encode_ipv6(field: u8, value: u128) -> Vec<u8> {
1530 let mut buf = Vec::with_capacity(20);
1531 let oxm_header = ((OxmClass::OpenflowBasic as u32) << 16) | ((field as u32) << 9) | 16;
1533 buf.extend(oxm_header.to_be_bytes());
1534 buf.extend(value.to_be_bytes());
1535 buf
1536}
1537
1538fn encode_ipv6_masked(field: u8, value: u128, mask: u128) -> Vec<u8> {
1539 let mut buf = Vec::with_capacity(36);
1540 let oxm_header = ((OxmClass::OpenflowBasic as u32) << 16) | ((field as u32) << 9) | (1 << 8) | 32;
1542 buf.extend(oxm_header.to_be_bytes());
1543 buf.extend(value.to_be_bytes());
1544 buf.extend(mask.to_be_bytes());
1545 buf
1546}
1547
1548#[cfg(test)]
1549mod tests {
1550 use super::*;
1551
1552 #[test]
1553 fn match_type_values() {
1554 assert_eq!(MatchType::Standard as u16, 0);
1555 assert_eq!(MatchType::Oxm as u16, 1);
1556 }
1557
1558 #[test]
1559 fn encode_empty_match() {
1560 let m = Match::new();
1561 let bytes = m.encode();
1562 assert_eq!(bytes.len(), 8);
1564 assert_eq!(&bytes[0..2], &[0x00, 0x01]);
1566 assert_eq!(&bytes[2..4], &[0x00, 0x04]);
1568 assert_eq!(&bytes[4..8], &[0, 0, 0, 0]);
1570 }
1571
1572 #[test]
1573 fn encode_in_port_match() {
1574 let m = Match::new().in_port(1);
1575 let bytes = m.encode();
1576 assert_eq!(bytes.len(), 16);
1578 assert_eq!(&bytes[0..2], &[0x00, 0x01]);
1580 assert_eq!(&bytes[2..4], &[0x00, 0x0c]);
1582 let expected_oxm: u32 = (0x8000 << 16) | (0 << 9) | 4;
1584 assert_eq!(&bytes[4..8], &expected_oxm.to_be_bytes());
1585 assert_eq!(&bytes[8..12], &[0x00, 0x00, 0x00, 0x01]);
1587 }
1588
1589 #[test]
1590 fn encode_eth_type_match() {
1591 let m = Match::new().eth_type(0x0800);
1592 let bytes = m.encode();
1593 assert_eq!(bytes.len(), 16);
1595 assert_eq!(&bytes[2..4], &[0x00, 0x0a]);
1597 let expected_oxm: u32 = (0x8000 << 16) | (5 << 9) | 2;
1599 assert_eq!(&bytes[4..8], &expected_oxm.to_be_bytes());
1600 assert_eq!(&bytes[8..10], &[0x08, 0x00]);
1602 }
1603
1604 #[test]
1605 fn encode_ipv4_dst_with_prefix() {
1606 let m = Match::new().ipv4_dst("10.0.0.0".parse().unwrap(), 24);
1607 let bytes = m.encode();
1608 assert_eq!(bytes.len(), 24);
1610 let eth_type_oxm: u32 = (0x8000 << 16) | (5 << 9) | 2;
1613 assert_eq!(&bytes[4..8], ð_type_oxm.to_be_bytes());
1614 assert_eq!(&bytes[8..10], &[0x08, 0x00]); }
1616
1617 #[test]
1618 fn encode_tcp_dst_match() {
1619 let m = Match::new().eth_type(0x0800).ip_proto(6).tcp_dst(80);
1620 let bytes = m.encode();
1621 assert_eq!(bytes.len(), 24);
1623 }
1624
1625 #[test]
1626 fn encode_eth_dst_match() {
1627 let mac: MacAddr = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55];
1628 let m = Match::new().eth_dst(mac);
1629 let bytes = m.encode();
1630 assert_eq!(bytes.len(), 16);
1632 let expected_oxm: u32 = (0x8000 << 16) | (3 << 9) | 6;
1634 assert_eq!(&bytes[4..8], &expected_oxm.to_be_bytes());
1635 assert_eq!(&bytes[8..14], &mac);
1637 }
1638
1639 #[test]
1640 fn encode_vlan_vid_match() {
1641 let m = Match::new().vlan_vid(100);
1642 let bytes = m.encode();
1643 assert_eq!(bytes.len(), 16);
1645 let expected_oxm: u32 = (0x8000 << 16) | (6 << 9) | 2;
1647 assert_eq!(&bytes[4..8], &expected_oxm.to_be_bytes());
1648 assert_eq!(&bytes[8..10], &[0x10, 0x64]);
1650 }
1651
1652 #[test]
1653 fn encode_tunnel_id_match() {
1654 let m = Match::new().tunnel_id(0x1234);
1655 let bytes = m.encode();
1656 assert_eq!(bytes.len(), 16);
1658 }
1659
1660 #[test]
1661 fn encode_multiple_fields() {
1662 let m = Match::new()
1663 .in_port(1)
1664 .eth_type(0x0800)
1665 .ipv4_dst("192.168.1.0".parse().unwrap(), 24);
1666 let bytes = m.encode();
1667 assert_eq!(bytes.len() % 8, 0);
1669 assert_eq!(&bytes[0..2], &[0x00, 0x01]);
1671 }
1672
1673 #[test]
1674 fn match_8_byte_alignment() {
1675 let m1 = Match::new().in_port(1);
1677 assert_eq!(m1.encode().len() % 8, 0);
1678
1679 let m2 = Match::new().eth_type(0x0800);
1680 assert_eq!(m2.encode().len() % 8, 0);
1681
1682 let m3 = Match::new().ip_proto(6);
1683 assert_eq!(m3.encode().len() % 8, 0);
1684
1685 let m4 = Match::new()
1686 .in_port(1)
1687 .eth_type(0x0800)
1688 .ip_proto(6)
1689 .tcp_dst(80);
1690 assert_eq!(m4.encode().len() % 8, 0);
1691 }
1692
1693 #[test]
1696 fn decode_empty_match() {
1697 let data = [0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00];
1699 let (m, len) = Match::decode(&data).unwrap();
1700 assert_eq!(len, 8);
1701 assert!(m.is_empty());
1702 }
1703
1704 #[test]
1705 fn decode_in_port() {
1706 let original = Match::new().in_port(42);
1707 let encoded = original.encode();
1708 let (decoded, _) = Match::decode(&encoded).unwrap();
1709 assert_eq!(decoded.in_port, Some(42));
1710 }
1711
1712 #[test]
1713 fn decode_eth_type() {
1714 let original = Match::new().eth_type(0x0800);
1715 let encoded = original.encode();
1716 let (decoded, _) = Match::decode(&encoded).unwrap();
1717 assert_eq!(decoded.eth_type, Some(0x0800));
1718 }
1719
1720 #[test]
1721 fn decode_vlan_vid() {
1722 let original = Match::new().vlan_vid(100);
1723 let encoded = original.encode();
1724 let (decoded, _) = Match::decode(&encoded).unwrap();
1725 assert_eq!(decoded.vlan_vid, Some(100));
1726 }
1727
1728 #[test]
1729 fn decode_ipv4_dst() {
1730 let original = Match::new().ipv4_dst("10.0.0.0".parse().unwrap(), 24);
1731 let encoded = original.encode();
1732 let (decoded, _) = Match::decode(&encoded).unwrap();
1733 assert_eq!(decoded.ipv4_dst, Some("10.0.0.0".parse().unwrap()));
1734 assert_eq!(decoded.ipv4_dst_mask, Some(24));
1735 }
1736
1737 #[test]
1738 fn decode_tcp_dst() {
1739 let original = Match::new().eth_type(0x0800).ip_proto(6).tcp_dst(80);
1740 let encoded = original.encode();
1741 let (decoded, _) = Match::decode(&encoded).unwrap();
1742 assert_eq!(decoded.eth_type, Some(0x0800));
1743 assert_eq!(decoded.ip_proto, Some(6));
1744 assert_eq!(decoded.tcp_dst, Some(80));
1745 }
1746
1747 #[test]
1748 fn decode_eth_dst() {
1749 let mac: MacAddr = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55];
1750 let original = Match::new().eth_dst(mac);
1751 let encoded = original.encode();
1752 let (decoded, _) = Match::decode(&encoded).unwrap();
1753 assert_eq!(decoded.eth_dst, Some(mac));
1754 }
1755
1756 #[test]
1757 fn decode_multiple_fields() {
1758 let original = Match::new()
1759 .in_port(1)
1760 .eth_type(0x0800)
1761 .ip_proto(6)
1762 .tcp_dst(443);
1763 let encoded = original.encode();
1764 let (decoded, _) = Match::decode(&encoded).unwrap();
1765 assert_eq!(decoded.in_port, Some(1));
1766 assert_eq!(decoded.eth_type, Some(0x0800));
1767 assert_eq!(decoded.ip_proto, Some(6));
1768 assert_eq!(decoded.tcp_dst, Some(443));
1769 }
1770
1771 #[test]
1772 fn roundtrip_encode_decode() {
1773 let original = Match::new()
1775 .in_port(5)
1776 .eth_dst([0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff])
1777 .eth_type(0x0800)
1778 .ipv4_dst("192.168.1.0".parse().unwrap(), 24)
1779 .ip_proto(17)
1780 .udp_dst(53);
1781
1782 let encoded = original.encode();
1783 let (decoded, len) = Match::decode(&encoded).unwrap();
1784
1785 assert_eq!(len, encoded.len());
1786 assert_eq!(decoded.in_port, Some(5));
1787 assert_eq!(decoded.eth_dst, Some([0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]));
1788 assert_eq!(decoded.eth_type, Some(0x0800));
1789 assert_eq!(decoded.ipv4_dst, Some("192.168.1.0".parse().unwrap()));
1790 assert_eq!(decoded.ipv4_dst_mask, Some(24));
1791 assert_eq!(decoded.ip_proto, Some(17));
1792 assert_eq!(decoded.udp_dst, Some(53));
1793 }
1794
1795 #[test]
1796 fn mask_to_prefix_conversion() {
1797 assert_eq!(mask_to_prefix(0xffff_ffff), 32);
1798 assert_eq!(mask_to_prefix(0xffff_ff00), 24);
1799 assert_eq!(mask_to_prefix(0xffff_0000), 16);
1800 assert_eq!(mask_to_prefix(0xff00_0000), 8);
1801 assert_eq!(mask_to_prefix(0x0000_0000), 0);
1802 }
1803
1804 #[test]
1805 fn mask_to_prefix_v6_conversion() {
1806 assert_eq!(mask_to_prefix_v6(u128::MAX), 128);
1807 assert_eq!(mask_to_prefix_v6(u128::MAX << 64), 64);
1808 assert_eq!(mask_to_prefix_v6(0), 0);
1809 }
1810
1811 #[test]
1814 fn encode_ct_state() {
1815 use crate::oxm::ct_state;
1816 let m = Match::new().ct_state(ct_state::TRK | ct_state::EST);
1817 let bytes = m.encode();
1818 assert!(bytes.len() >= 8);
1820 assert_eq!(bytes.len() % 8, 0);
1822 }
1823
1824 #[test]
1825 fn encode_ct_state_masked() {
1826 use crate::oxm::ct_state;
1827 let m = Match::new().ct_state_masked(
1828 ct_state::TRK | ct_state::NEW,
1829 ct_state::TRK | ct_state::NEW,
1830 );
1831 let bytes = m.encode();
1832 assert!(bytes.len() >= 8);
1833 assert_eq!(bytes.len() % 8, 0);
1834 }
1835
1836 #[test]
1837 fn encode_ct_zone() {
1838 let m = Match::new().ct_zone(100);
1839 let bytes = m.encode();
1840 assert!(bytes.len() >= 8);
1841 assert_eq!(bytes.len() % 8, 0);
1842 }
1843
1844 #[test]
1845 fn encode_ct_mark() {
1846 let m = Match::new().ct_mark(0xaabbccdd);
1847 let bytes = m.encode();
1848 assert!(bytes.len() >= 8);
1849 assert_eq!(bytes.len() % 8, 0);
1850 }
1851
1852 #[test]
1853 fn encode_ct_mark_masked() {
1854 let m = Match::new().ct_mark_masked(0xff000000, 0xff000000);
1855 let bytes = m.encode();
1856 assert!(bytes.len() >= 8);
1857 assert_eq!(bytes.len() % 8, 0);
1858 }
1859
1860 #[test]
1861 fn roundtrip_ct_state() {
1862 use crate::oxm::ct_state;
1863 let state = ct_state::TRK | ct_state::EST;
1864 let original = Match::new().ct_state(state);
1865 let encoded = original.encode();
1866 let (decoded, _) = Match::decode(&encoded).unwrap();
1867 assert_eq!(decoded.ct_state, Some(state));
1868 }
1869
1870 #[test]
1871 fn roundtrip_ct_zone() {
1872 let original = Match::new().ct_zone(42);
1873 let encoded = original.encode();
1874 let (decoded, _) = Match::decode(&encoded).unwrap();
1875 assert_eq!(decoded.ct_zone, Some(42));
1876 }
1877
1878 #[test]
1879 fn roundtrip_ct_mark() {
1880 let original = Match::new().ct_mark(0x12345678);
1881 let encoded = original.encode();
1882 let (decoded, _) = Match::decode(&encoded).unwrap();
1883 assert_eq!(decoded.ct_mark, Some(0x12345678));
1884 }
1885
1886 #[test]
1887 fn stateful_firewall_match() {
1888 use crate::oxm::ct_state;
1889 let m = Match::new()
1891 .eth_type(0x0800)
1892 .ct_state(ct_state::TRK | ct_state::EST);
1893
1894 let bytes = m.encode();
1895 let (decoded, _) = Match::decode(&bytes).unwrap();
1896
1897 assert_eq!(decoded.eth_type, Some(0x0800));
1898 assert_eq!(decoded.ct_state, Some(ct_state::TRK | ct_state::EST));
1899 }
1900}