1use thiserror::Error;
4
5#[derive(Debug, Error)]
7pub enum Error {
8 #[error("transport error: {0}")]
10 Transport(#[from] rovs_transport::Error),
11
12 #[error("I/O error: {0}")]
14 Io(#[from] std::io::Error),
15
16 #[error("unsupported OpenFlow version: {0}")]
18 UnsupportedVersion(u8),
19
20 #[error("parse error: {0}")]
22 Parse(String),
23
24 #[error("invalid message: {0}")]
26 InvalidMessage(String),
27
28 #[error("connection closed")]
30 ConnectionClosed,
31
32 #[error("timeout")]
34 Timeout,
35
36 #[error("{0}")]
38 OfError(OfError),
39}
40
41#[derive(Debug, Clone)]
43pub struct OfError {
44 pub error_type: OfErrorType,
46 pub code: u16,
48 pub data: Vec<u8>,
50}
51
52impl std::fmt::Display for OfError {
53 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54 write!(f, "{}: ", self.error_type)?;
55 match self.error_type {
56 OfErrorType::HelloFailed => write!(f, "{}", HelloFailedCode::from(self.code)),
57 OfErrorType::BadRequest => write!(f, "{}", BadRequestCode::from(self.code)),
58 OfErrorType::BadAction => write!(f, "{}", BadActionCode::from(self.code)),
59 OfErrorType::BadInstruction => write!(f, "{}", BadInstructionCode::from(self.code)),
60 OfErrorType::BadMatch => write!(f, "{}", BadMatchCode::from(self.code)),
61 OfErrorType::FlowModFailed => write!(f, "{}", FlowModFailedCode::from(self.code)),
62 OfErrorType::GroupModFailed => write!(f, "{}", GroupModFailedCode::from(self.code)),
63 OfErrorType::PortModFailed => write!(f, "{}", PortModFailedCode::from(self.code)),
64 OfErrorType::TableModFailed => write!(f, "{}", TableModFailedCode::from(self.code)),
65 OfErrorType::MeterModFailed => write!(f, "{}", MeterModFailedCode::from(self.code)),
66 OfErrorType::TableFeaturesFailed => {
67 write!(f, "{}", TableFeaturesFailedCode::from(self.code))
68 }
69 OfErrorType::Unknown(_) => write!(f, "code {}", self.code),
70 }
71 }
72}
73
74impl OfError {
75 pub fn parse(body: &[u8]) -> Result<Self, Error> {
77 if body.len() < 4 {
78 return Err(Error::Parse("error message too short".into()));
79 }
80
81 let error_type = u16::from_be_bytes([body[0], body[1]]);
82 let code = u16::from_be_bytes([body[2], body[3]]);
83 let data = body.get(4..).unwrap_or(&[]).to_vec();
84
85 Ok(Self {
86 error_type: OfErrorType::from(error_type),
87 code,
88 data,
89 })
90 }
91}
92
93#[derive(Debug, Clone, Copy, PartialEq, Eq)]
95pub enum OfErrorType {
96 HelloFailed,
98 BadRequest,
100 BadAction,
102 BadInstruction,
104 BadMatch,
106 FlowModFailed,
108 GroupModFailed,
110 PortModFailed,
112 TableModFailed,
114 MeterModFailed,
116 TableFeaturesFailed,
118 Unknown(u16),
120}
121
122impl From<u16> for OfErrorType {
123 fn from(v: u16) -> Self {
124 match v {
125 0 => Self::HelloFailed,
126 1 => Self::BadRequest,
127 2 => Self::BadAction,
128 3 => Self::BadInstruction,
129 4 => Self::BadMatch,
130 5 => Self::FlowModFailed,
131 6 => Self::GroupModFailed,
132 7 => Self::PortModFailed,
133 8 => Self::TableModFailed,
134 12 => Self::MeterModFailed,
135 13 => Self::TableFeaturesFailed,
136 _ => Self::Unknown(v),
137 }
138 }
139}
140
141impl std::fmt::Display for OfErrorType {
142 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
143 match self {
144 Self::HelloFailed => write!(f, "HELLO_FAILED"),
145 Self::BadRequest => write!(f, "BAD_REQUEST"),
146 Self::BadAction => write!(f, "BAD_ACTION"),
147 Self::BadInstruction => write!(f, "BAD_INSTRUCTION"),
148 Self::BadMatch => write!(f, "BAD_MATCH"),
149 Self::FlowModFailed => write!(f, "FLOW_MOD_FAILED"),
150 Self::GroupModFailed => write!(f, "GROUP_MOD_FAILED"),
151 Self::PortModFailed => write!(f, "PORT_MOD_FAILED"),
152 Self::TableModFailed => write!(f, "TABLE_MOD_FAILED"),
153 Self::MeterModFailed => write!(f, "METER_MOD_FAILED"),
154 Self::TableFeaturesFailed => write!(f, "TABLE_FEATURES_FAILED"),
155 Self::Unknown(v) => write!(f, "UNKNOWN({v})"),
156 }
157 }
158}
159
160#[derive(Debug, Clone, Copy, PartialEq, Eq)]
162pub enum HelloFailedCode {
163 Incompatible,
165 EpermError,
167 Unknown(u16),
169}
170
171impl From<u16> for HelloFailedCode {
172 fn from(v: u16) -> Self {
173 match v {
174 0 => Self::Incompatible,
175 1 => Self::EpermError,
176 _ => Self::Unknown(v),
177 }
178 }
179}
180
181impl std::fmt::Display for HelloFailedCode {
182 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
183 match self {
184 Self::Incompatible => write!(f, "incompatible version"),
185 Self::EpermError => write!(f, "permissions error"),
186 Self::Unknown(v) => write!(f, "unknown code {v}"),
187 }
188 }
189}
190
191#[derive(Debug, Clone, Copy, PartialEq, Eq)]
193pub enum BadRequestCode {
194 BadVersion,
196 BadType,
198 BadMultipart,
200 BadExperimenter,
202 BadExpType,
204 Eperm,
206 BadLen,
208 BufferEmpty,
210 BufferUnknown,
212 BadTableId,
214 IsSlave,
216 BadPort,
218 BadPacket,
220 MultipartBufferOverflow,
222 Unknown(u16),
224}
225
226impl From<u16> for BadRequestCode {
227 fn from(v: u16) -> Self {
228 match v {
229 0 => Self::BadVersion,
230 1 => Self::BadType,
231 2 => Self::BadMultipart,
232 3 => Self::BadExperimenter,
233 4 => Self::BadExpType,
234 5 => Self::Eperm,
235 6 => Self::BadLen,
236 7 => Self::BufferEmpty,
237 8 => Self::BufferUnknown,
238 9 => Self::BadTableId,
239 10 => Self::IsSlave,
240 11 => Self::BadPort,
241 12 => Self::BadPacket,
242 13 => Self::MultipartBufferOverflow,
243 _ => Self::Unknown(v),
244 }
245 }
246}
247
248impl std::fmt::Display for BadRequestCode {
249 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
250 match self {
251 Self::BadVersion => write!(f, "unknown version"),
252 Self::BadType => write!(f, "unknown message type"),
253 Self::BadMultipart => write!(f, "unknown multipart type"),
254 Self::BadExperimenter => write!(f, "unknown experimenter ID"),
255 Self::BadExpType => write!(f, "unknown experimenter type"),
256 Self::Eperm => write!(f, "permissions error"),
257 Self::BadLen => write!(f, "wrong request length"),
258 Self::BufferEmpty => write!(f, "buffer does not exist"),
259 Self::BufferUnknown => write!(f, "buffer already used"),
260 Self::BadTableId => write!(f, "invalid table ID"),
261 Self::IsSlave => write!(f, "controller is slave"),
262 Self::BadPort => write!(f, "invalid port"),
263 Self::BadPacket => write!(f, "invalid packet in buffer-id"),
264 Self::MultipartBufferOverflow => write!(f, "multipart request overflowed"),
265 Self::Unknown(v) => write!(f, "unknown code {v}"),
266 }
267 }
268}
269
270#[derive(Debug, Clone, Copy, PartialEq, Eq)]
272pub enum BadActionCode {
273 BadType,
275 BadLen,
277 BadExperimenter,
279 BadExpType,
281 BadOutPort,
283 BadArgument,
285 Eperm,
287 TooMany,
289 BadQueue,
291 BadOutGroup,
293 MatchInconsistent,
295 UnsupportedOrder,
297 BadTag,
299 BadSetType,
301 BadSetLen,
303 BadSetArgument,
305 Unknown(u16),
307}
308
309impl From<u16> for BadActionCode {
310 fn from(v: u16) -> Self {
311 match v {
312 0 => Self::BadType,
313 1 => Self::BadLen,
314 2 => Self::BadExperimenter,
315 3 => Self::BadExpType,
316 4 => Self::BadOutPort,
317 5 => Self::BadArgument,
318 6 => Self::Eperm,
319 7 => Self::TooMany,
320 8 => Self::BadQueue,
321 9 => Self::BadOutGroup,
322 10 => Self::MatchInconsistent,
323 11 => Self::UnsupportedOrder,
324 12 => Self::BadTag,
325 13 => Self::BadSetType,
326 14 => Self::BadSetLen,
327 15 => Self::BadSetArgument,
328 _ => Self::Unknown(v),
329 }
330 }
331}
332
333impl std::fmt::Display for BadActionCode {
334 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
335 match self {
336 Self::BadType => write!(f, "unknown action type"),
337 Self::BadLen => write!(f, "length problem in actions"),
338 Self::BadExperimenter => write!(f, "unknown experimenter ID"),
339 Self::BadExpType => write!(f, "unknown action for experimenter"),
340 Self::BadOutPort => write!(f, "problem validating output port"),
341 Self::BadArgument => write!(f, "bad action argument"),
342 Self::Eperm => write!(f, "permissions error"),
343 Self::TooMany => write!(f, "too many actions"),
344 Self::BadQueue => write!(f, "problem validating output queue"),
345 Self::BadOutGroup => write!(f, "invalid group ID"),
346 Self::MatchInconsistent => write!(f, "action can't apply for this match"),
347 Self::UnsupportedOrder => write!(f, "action order unsupported"),
348 Self::BadTag => write!(f, "unsupported tag/encap"),
349 Self::BadSetType => write!(f, "unsupported SET_FIELD type"),
350 Self::BadSetLen => write!(f, "length problem in SET_FIELD"),
351 Self::BadSetArgument => write!(f, "bad argument in SET_FIELD"),
352 Self::Unknown(v) => write!(f, "unknown code {v}"),
353 }
354 }
355}
356
357#[derive(Debug, Clone, Copy, PartialEq, Eq)]
359pub enum BadInstructionCode {
360 UnknownInst,
362 UnsupInst,
364 BadTableId,
366 UnsupMetadata,
368 UnsupMetadataMask,
370 BadExperimenter,
372 BadExpType,
374 BadLen,
376 Eperm,
378 Unknown(u16),
380}
381
382impl From<u16> for BadInstructionCode {
383 fn from(v: u16) -> Self {
384 match v {
385 0 => Self::UnknownInst,
386 1 => Self::UnsupInst,
387 2 => Self::BadTableId,
388 3 => Self::UnsupMetadata,
389 4 => Self::UnsupMetadataMask,
390 5 => Self::BadExperimenter,
391 6 => Self::BadExpType,
392 7 => Self::BadLen,
393 8 => Self::Eperm,
394 _ => Self::Unknown(v),
395 }
396 }
397}
398
399impl std::fmt::Display for BadInstructionCode {
400 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
401 match self {
402 Self::UnknownInst => write!(f, "unknown instruction type"),
403 Self::UnsupInst => write!(f, "unsupported instruction"),
404 Self::BadTableId => write!(f, "invalid table ID"),
405 Self::UnsupMetadata => write!(f, "metadata mask unsupported"),
406 Self::UnsupMetadataMask => write!(f, "metadata mask unsupported in write"),
407 Self::BadExperimenter => write!(f, "unknown experimenter ID"),
408 Self::BadExpType => write!(f, "unknown instruction for experimenter"),
409 Self::BadLen => write!(f, "length problem in instructions"),
410 Self::Eperm => write!(f, "permissions error"),
411 Self::Unknown(v) => write!(f, "unknown code {v}"),
412 }
413 }
414}
415
416#[derive(Debug, Clone, Copy, PartialEq, Eq)]
418pub enum BadMatchCode {
419 BadType,
421 BadLen,
423 BadTag,
425 BadDlAddrMask,
427 BadNwAddrMask,
429 BadWildcards,
431 BadField,
433 BadValue,
435 BadMask,
437 BadPrereq,
439 DupField,
441 Eperm,
443 Unknown(u16),
445}
446
447impl From<u16> for BadMatchCode {
448 fn from(v: u16) -> Self {
449 match v {
450 0 => Self::BadType,
451 1 => Self::BadLen,
452 2 => Self::BadTag,
453 3 => Self::BadDlAddrMask,
454 4 => Self::BadNwAddrMask,
455 5 => Self::BadWildcards,
456 6 => Self::BadField,
457 7 => Self::BadValue,
458 8 => Self::BadMask,
459 9 => Self::BadPrereq,
460 10 => Self::DupField,
461 11 => Self::Eperm,
462 _ => Self::Unknown(v),
463 }
464 }
465}
466
467impl std::fmt::Display for BadMatchCode {
468 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
469 match self {
470 Self::BadType => write!(f, "unsupported match type"),
471 Self::BadLen => write!(f, "length problem in match"),
472 Self::BadTag => write!(f, "unsupported tag/encap"),
473 Self::BadDlAddrMask => write!(f, "unsupported datalink address mask"),
474 Self::BadNwAddrMask => write!(f, "unsupported network address mask"),
475 Self::BadWildcards => write!(f, "unsupported field combination"),
476 Self::BadField => write!(f, "unsupported field type"),
477 Self::BadValue => write!(f, "unsupported value in match field"),
478 Self::BadMask => write!(f, "unsupported mask specified"),
479 Self::BadPrereq => write!(f, "prerequisite not met"),
480 Self::DupField => write!(f, "field appeared more than once"),
481 Self::Eperm => write!(f, "permissions error"),
482 Self::Unknown(v) => write!(f, "unknown code {v}"),
483 }
484 }
485}
486
487#[derive(Debug, Clone, Copy, PartialEq, Eq)]
489pub enum FlowModFailedCode {
490 Unknown,
492 TableFull,
494 BadTableId,
496 Overlap,
498 Eperm,
500 BadTimeout,
502 BadCommand,
504 BadFlags,
506 UnknownCode(u16),
508}
509
510impl From<u16> for FlowModFailedCode {
511 fn from(v: u16) -> Self {
512 match v {
513 0 => Self::Unknown,
514 1 => Self::TableFull,
515 2 => Self::BadTableId,
516 3 => Self::Overlap,
517 4 => Self::Eperm,
518 5 => Self::BadTimeout,
519 6 => Self::BadCommand,
520 7 => Self::BadFlags,
521 _ => Self::UnknownCode(v),
522 }
523 }
524}
525
526impl std::fmt::Display for FlowModFailedCode {
527 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
528 match self {
529 Self::Unknown => write!(f, "unspecified error"),
530 Self::TableFull => write!(f, "table full"),
531 Self::BadTableId => write!(f, "table does not exist"),
532 Self::Overlap => write!(f, "overlapping flow entry"),
533 Self::Eperm => write!(f, "permissions error"),
534 Self::BadTimeout => write!(f, "bad timeout"),
535 Self::BadCommand => write!(f, "unsupported command"),
536 Self::BadFlags => write!(f, "unsupported flags"),
537 Self::UnknownCode(v) => write!(f, "unknown code {v}"),
538 }
539 }
540}
541
542#[derive(Debug, Clone, Copy, PartialEq, Eq)]
544pub enum GroupModFailedCode {
545 GroupExists,
547 InvalidGroup,
549 UnknownGroup,
551 WeightUnsupported,
553 OutOfBuckets,
555 OutOfGroups,
557 ChainingUnsupported,
559 WatchUnsupported,
561 Loop,
563 ChainsNotSupported,
565 Unknown(u16),
567}
568
569impl From<u16> for GroupModFailedCode {
570 fn from(v: u16) -> Self {
571 match v {
572 0 => Self::GroupExists,
573 1 => Self::InvalidGroup,
574 2 => Self::WeightUnsupported,
575 3 => Self::OutOfGroups,
576 4 => Self::OutOfBuckets,
577 5 => Self::ChainingUnsupported,
578 6 => Self::WatchUnsupported,
579 7 => Self::Loop,
580 8 => Self::UnknownGroup,
581 9 => Self::ChainsNotSupported,
582 _ => Self::Unknown(v),
583 }
584 }
585}
586
587impl std::fmt::Display for GroupModFailedCode {
588 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
589 match self {
590 Self::GroupExists => write!(f, "group already exists"),
591 Self::InvalidGroup => write!(f, "invalid group"),
592 Self::UnknownGroup => write!(f, "group does not exist"),
593 Self::WeightUnsupported => write!(f, "bucket weight unsupported"),
594 Self::OutOfBuckets => write!(f, "bucket maximum exceeded"),
595 Self::OutOfGroups => write!(f, "group maximum exceeded"),
596 Self::ChainingUnsupported => write!(f, "chaining unsupported"),
597 Self::WatchUnsupported => write!(f, "watch bucket unsupported"),
598 Self::Loop => write!(f, "loop in group"),
599 Self::ChainsNotSupported => write!(f, "chains not supported"),
600 Self::Unknown(v) => write!(f, "unknown code {v}"),
601 }
602 }
603}
604
605#[derive(Debug, Clone, Copy, PartialEq, Eq)]
607pub enum PortModFailedCode {
608 BadPort,
610 BadHwAddr,
612 BadConfig,
614 BadAdvertise,
616 Eperm,
618 Unknown(u16),
620}
621
622impl From<u16> for PortModFailedCode {
623 fn from(v: u16) -> Self {
624 match v {
625 0 => Self::BadPort,
626 1 => Self::BadHwAddr,
627 2 => Self::BadConfig,
628 3 => Self::BadAdvertise,
629 4 => Self::Eperm,
630 _ => Self::Unknown(v),
631 }
632 }
633}
634
635impl std::fmt::Display for PortModFailedCode {
636 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
637 match self {
638 Self::BadPort => write!(f, "port does not exist"),
639 Self::BadHwAddr => write!(f, "hardware address mismatch"),
640 Self::BadConfig => write!(f, "invalid config"),
641 Self::BadAdvertise => write!(f, "invalid advertise"),
642 Self::Eperm => write!(f, "permissions error"),
643 Self::Unknown(v) => write!(f, "unknown code {v}"),
644 }
645 }
646}
647
648#[derive(Debug, Clone, Copy, PartialEq, Eq)]
650pub enum TableModFailedCode {
651 BadTable,
653 BadConfig,
655 Eperm,
657 Unknown(u16),
659}
660
661impl From<u16> for TableModFailedCode {
662 fn from(v: u16) -> Self {
663 match v {
664 0 => Self::BadTable,
665 1 => Self::BadConfig,
666 2 => Self::Eperm,
667 _ => Self::Unknown(v),
668 }
669 }
670}
671
672impl std::fmt::Display for TableModFailedCode {
673 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
674 match self {
675 Self::BadTable => write!(f, "table does not exist"),
676 Self::BadConfig => write!(f, "invalid config"),
677 Self::Eperm => write!(f, "permissions error"),
678 Self::Unknown(v) => write!(f, "unknown code {v}"),
679 }
680 }
681}
682
683#[derive(Debug, Clone, Copy, PartialEq, Eq)]
685pub enum MeterModFailedCode {
686 Unknown,
688 MeterExists,
690 InvalidMeter,
692 UnknownMeter,
694 BadCommand,
696 BadFlags,
698 BadRate,
700 BadBurst,
702 BadBand,
704 BadBandValue,
706 OutOfMeters,
708 OutOfBands,
710 UnknownCode(u16),
712}
713
714impl From<u16> for MeterModFailedCode {
715 fn from(v: u16) -> Self {
716 match v {
717 0 => Self::Unknown,
718 1 => Self::MeterExists,
719 2 => Self::InvalidMeter,
720 3 => Self::UnknownMeter,
721 4 => Self::BadCommand,
722 5 => Self::BadFlags,
723 6 => Self::BadRate,
724 7 => Self::BadBurst,
725 8 => Self::BadBand,
726 9 => Self::BadBandValue,
727 10 => Self::OutOfMeters,
728 11 => Self::OutOfBands,
729 _ => Self::UnknownCode(v),
730 }
731 }
732}
733
734impl std::fmt::Display for MeterModFailedCode {
735 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
736 match self {
737 Self::Unknown => write!(f, "unspecified error"),
738 Self::MeterExists => write!(f, "meter already exists"),
739 Self::InvalidMeter => write!(f, "invalid meter"),
740 Self::UnknownMeter => write!(f, "meter does not exist"),
741 Self::BadCommand => write!(f, "unsupported command"),
742 Self::BadFlags => write!(f, "unsupported flags"),
743 Self::BadRate => write!(f, "rate unsupported"),
744 Self::BadBurst => write!(f, "burst size unsupported"),
745 Self::BadBand => write!(f, "band unsupported"),
746 Self::BadBandValue => write!(f, "band value unsupported"),
747 Self::OutOfMeters => write!(f, "meter maximum exceeded"),
748 Self::OutOfBands => write!(f, "maximum bands exceeded"),
749 Self::UnknownCode(v) => write!(f, "unknown code {v}"),
750 }
751 }
752}
753
754#[derive(Debug, Clone, Copy, PartialEq, Eq)]
756pub enum TableFeaturesFailedCode {
757 BadTable,
759 BadMetadata,
761 BadType,
763 BadLen,
765 BadArgument,
767 Eperm,
769 Unknown(u16),
771}
772
773impl From<u16> for TableFeaturesFailedCode {
774 fn from(v: u16) -> Self {
775 match v {
776 0 => Self::BadTable,
777 1 => Self::BadMetadata,
778 2 => Self::BadType,
779 3 => Self::BadLen,
780 4 => Self::BadArgument,
781 5 => Self::Eperm,
782 _ => Self::Unknown(v),
783 }
784 }
785}
786
787impl std::fmt::Display for TableFeaturesFailedCode {
788 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
789 match self {
790 Self::BadTable => write!(f, "table does not exist"),
791 Self::BadMetadata => write!(f, "invalid metadata mask"),
792 Self::BadType => write!(f, "unknown property type"),
793 Self::BadLen => write!(f, "length problem"),
794 Self::BadArgument => write!(f, "unsupported property value"),
795 Self::Eperm => write!(f, "permissions error"),
796 Self::Unknown(v) => write!(f, "unknown code {v}"),
797 }
798 }
799}
800
801#[cfg(test)]
802mod tests {
803 use super::*;
804
805 #[test]
806 fn parse_of_error_flow_mod_failed() {
807 let body = [0x00, 0x05, 0x00, 0x01, 0xde, 0xad, 0xbe, 0xef];
809 let err = OfError::parse(&body).unwrap();
810
811 assert_eq!(err.error_type, OfErrorType::FlowModFailed);
812 assert_eq!(err.code, 1);
813 assert_eq!(err.data, vec![0xde, 0xad, 0xbe, 0xef]);
814
815 let msg = err.to_string();
816 assert!(msg.contains("FLOW_MOD_FAILED"));
817 assert!(msg.contains("table full"));
818 }
819
820 #[test]
821 fn parse_of_error_bad_match() {
822 let body = [0x00, 0x04, 0x00, 0x09];
824 let err = OfError::parse(&body).unwrap();
825
826 assert_eq!(err.error_type, OfErrorType::BadMatch);
827 assert_eq!(err.code, 9);
828 assert!(err.data.is_empty());
829
830 let msg = err.to_string();
831 assert!(msg.contains("BAD_MATCH"));
832 assert!(msg.contains("prerequisite not met"));
833 }
834
835 #[test]
836 fn parse_of_error_too_short() {
837 let body = [0x00, 0x01];
838 assert!(OfError::parse(&body).is_err());
839 }
840
841 #[test]
842 fn of_error_type_from_u16() {
843 assert_eq!(OfErrorType::from(0), OfErrorType::HelloFailed);
844 assert_eq!(OfErrorType::from(1), OfErrorType::BadRequest);
845 assert_eq!(OfErrorType::from(5), OfErrorType::FlowModFailed);
846 assert_eq!(OfErrorType::from(99), OfErrorType::Unknown(99));
847 }
848
849 #[test]
850 fn flow_mod_failed_codes() {
851 assert_eq!(
852 FlowModFailedCode::from(1).to_string(),
853 "table full"
854 );
855 assert_eq!(
856 FlowModFailedCode::from(3).to_string(),
857 "overlapping flow entry"
858 );
859 assert_eq!(
860 FlowModFailedCode::from(4).to_string(),
861 "permissions error"
862 );
863 }
864
865 #[test]
866 fn bad_action_codes() {
867 assert_eq!(
868 BadActionCode::from(0).to_string(),
869 "unknown action type"
870 );
871 assert_eq!(
872 BadActionCode::from(4).to_string(),
873 "problem validating output port"
874 );
875 }
876
877 #[test]
878 fn bad_match_codes() {
879 assert_eq!(
880 BadMatchCode::from(9).to_string(),
881 "prerequisite not met"
882 );
883 assert_eq!(
884 BadMatchCode::from(10).to_string(),
885 "field appeared more than once"
886 );
887 }
888}