Skip to main content

rovs_openflow/
error.rs

1//! OpenFlow error types.
2
3use thiserror::Error;
4
5/// Errors that can occur in OpenFlow operations.
6#[derive(Debug, Error)]
7pub enum Error {
8    /// Transport error
9    #[error("transport error: {0}")]
10    Transport(#[from] rovs_transport::Error),
11
12    /// I/O error
13    #[error("I/O error: {0}")]
14    Io(#[from] std::io::Error),
15
16    /// Unsupported protocol version
17    #[error("unsupported OpenFlow version: {0}")]
18    UnsupportedVersion(u8),
19
20    /// Message parsing error
21    #[error("parse error: {0}")]
22    Parse(String),
23
24    /// Invalid message
25    #[error("invalid message: {0}")]
26    InvalidMessage(String),
27
28    /// Connection closed
29    #[error("connection closed")]
30    ConnectionClosed,
31
32    /// Timeout
33    #[error("timeout")]
34    Timeout,
35
36    /// OpenFlow error from switch
37    #[error("{0}")]
38    OfError(OfError),
39}
40
41/// OpenFlow error message from the switch.
42#[derive(Debug, Clone)]
43pub struct OfError {
44    /// Error type
45    pub error_type: OfErrorType,
46    /// Error code (type-specific)
47    pub code: u16,
48    /// Original request data (up to 64 bytes)
49    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    /// Parse an OpenFlow error from message body.
76    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/// OpenFlow error types (OF 1.3).
94#[derive(Debug, Clone, Copy, PartialEq, Eq)]
95pub enum OfErrorType {
96    /// Hello protocol failed
97    HelloFailed,
98    /// Request was not understood
99    BadRequest,
100    /// Error in action description
101    BadAction,
102    /// Error in instruction list
103    BadInstruction,
104    /// Error in match
105    BadMatch,
106    /// Problem modifying flow entry
107    FlowModFailed,
108    /// Problem modifying group entry
109    GroupModFailed,
110    /// Port mod request failed
111    PortModFailed,
112    /// Table mod request failed
113    TableModFailed,
114    /// Meter mod request failed
115    MeterModFailed,
116    /// Table features request failed
117    TableFeaturesFailed,
118    /// Unknown error type
119    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/// Hello failed error codes.
161#[derive(Debug, Clone, Copy, PartialEq, Eq)]
162pub enum HelloFailedCode {
163    /// No compatible version
164    Incompatible,
165    /// Permissions error
166    EpermError,
167    /// Unknown code
168    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/// Bad request error codes.
192#[derive(Debug, Clone, Copy, PartialEq, Eq)]
193pub enum BadRequestCode {
194    /// Unknown or unsupported version
195    BadVersion,
196    /// Unknown or unsupported message type
197    BadType,
198    /// Unknown or unsupported multipart type
199    BadMultipart,
200    /// Unknown or unsupported experimenter ID
201    BadExperimenter,
202    /// Unknown or unsupported experimenter type
203    BadExpType,
204    /// Permissions error
205    Eperm,
206    /// Wrong request length
207    BadLen,
208    /// Specified buffer does not exist
209    BufferEmpty,
210    /// Specified buffer already used
211    BufferUnknown,
212    /// Specified table-id invalid
213    BadTableId,
214    /// Denied because controller is slave
215    IsSlave,
216    /// Invalid port
217    BadPort,
218    /// Invalid packet in buffer-id
219    BadPacket,
220    /// Multipart request overflowed
221    MultipartBufferOverflow,
222    /// Unknown code
223    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/// Bad action error codes.
271#[derive(Debug, Clone, Copy, PartialEq, Eq)]
272pub enum BadActionCode {
273    /// Unknown action type
274    BadType,
275    /// Length problem in actions
276    BadLen,
277    /// Unknown experimenter ID
278    BadExperimenter,
279    /// Unknown action for experimenter ID
280    BadExpType,
281    /// Problem validating output port
282    BadOutPort,
283    /// Bad action argument
284    BadArgument,
285    /// Permissions error
286    Eperm,
287    /// Too many actions
288    TooMany,
289    /// Problem validating output queue
290    BadQueue,
291    /// Invalid group ID
292    BadOutGroup,
293    /// Action can't apply - match inconsistent
294    MatchInconsistent,
295    /// Action order unsupported for Apply-Actions
296    UnsupportedOrder,
297    /// Actions use unsupported tag/encap
298    BadTag,
299    /// Unsupported type in SET_FIELD
300    BadSetType,
301    /// Length problem in SET_FIELD
302    BadSetLen,
303    /// Bad argument in SET_FIELD
304    BadSetArgument,
305    /// Unknown code
306    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/// Bad instruction error codes.
358#[derive(Debug, Clone, Copy, PartialEq, Eq)]
359pub enum BadInstructionCode {
360    /// Unknown instruction type
361    UnknownInst,
362    /// Switch does not support some prerequisite
363    UnsupInst,
364    /// Invalid table ID
365    BadTableId,
366    /// Metadata mask value unsupported
367    UnsupMetadata,
368    /// Metadata mask value unsupported in write
369    UnsupMetadataMask,
370    /// Unknown experimenter ID
371    BadExperimenter,
372    /// Unknown instruction for experimenter
373    BadExpType,
374    /// Length problem in instructions
375    BadLen,
376    /// Permissions error
377    Eperm,
378    /// Unknown code
379    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/// Bad match error codes.
417#[derive(Debug, Clone, Copy, PartialEq, Eq)]
418pub enum BadMatchCode {
419    /// Unsupported match type
420    BadType,
421    /// Length problem in match
422    BadLen,
423    /// Match uses unsupported tag/encap
424    BadTag,
425    /// Unsupported datalink addr mask
426    BadDlAddrMask,
427    /// Unsupported network addr mask
428    BadNwAddrMask,
429    /// Unsupported combination of fields
430    BadWildcards,
431    /// Unsupported field type
432    BadField,
433    /// Unsupported value in a match field
434    BadValue,
435    /// Unsupported mask specified
436    BadMask,
437    /// A prerequisite was not met
438    BadPrereq,
439    /// A field appeared more than once
440    DupField,
441    /// Permissions error
442    Eperm,
443    /// Unknown code
444    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/// Flow mod failed error codes.
488#[derive(Debug, Clone, Copy, PartialEq, Eq)]
489pub enum FlowModFailedCode {
490    /// Unspecified error
491    Unknown,
492    /// Flow not added - table full
493    TableFull,
494    /// Table does not exist
495    BadTableId,
496    /// Attempted to add overlapping flow
497    Overlap,
498    /// Permissions error
499    Eperm,
500    /// Flow not added - idle/hard timeout
501    BadTimeout,
502    /// Unsupported or unknown command
503    BadCommand,
504    /// Unsupported or unknown flags
505    BadFlags,
506    /// Unknown code
507    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/// Group mod failed error codes.
543#[derive(Debug, Clone, Copy, PartialEq, Eq)]
544pub enum GroupModFailedCode {
545    /// Group not added - already exists
546    GroupExists,
547    /// Group not added - invalid group
548    InvalidGroup,
549    /// Group not modified - does not exist
550    UnknownGroup,
551    /// Bucket weight unsupported
552    WeightUnsupported,
553    /// Group bucket maximum exceeded
554    OutOfBuckets,
555    /// Action bucket maximum exceeded
556    OutOfGroups,
557    /// Chaining not supported
558    ChainingUnsupported,
559    /// Watch bucket value unsupported
560    WatchUnsupported,
561    /// Group table full
562    Loop,
563    /// Group table full
564    ChainsNotSupported,
565    /// Unknown code
566    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/// Port mod failed error codes.
606#[derive(Debug, Clone, Copy, PartialEq, Eq)]
607pub enum PortModFailedCode {
608    /// Specified port does not exist
609    BadPort,
610    /// Specified hardware address mismatch
611    BadHwAddr,
612    /// Specified config is invalid
613    BadConfig,
614    /// Specified advertise is invalid
615    BadAdvertise,
616    /// Permissions error
617    Eperm,
618    /// Unknown code
619    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/// Table mod failed error codes.
649#[derive(Debug, Clone, Copy, PartialEq, Eq)]
650pub enum TableModFailedCode {
651    /// Specified table does not exist
652    BadTable,
653    /// Specified config is invalid
654    BadConfig,
655    /// Permissions error
656    Eperm,
657    /// Unknown code
658    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/// Meter mod failed error codes.
684#[derive(Debug, Clone, Copy, PartialEq, Eq)]
685pub enum MeterModFailedCode {
686    /// Unspecified error
687    Unknown,
688    /// Meter not added - already exists
689    MeterExists,
690    /// Meter not added - invalid meter
691    InvalidMeter,
692    /// Meter not modified - does not exist
693    UnknownMeter,
694    /// Unsupported or unknown command
695    BadCommand,
696    /// Flag configuration unsupported
697    BadFlags,
698    /// Rate unsupported
699    BadRate,
700    /// Burst size unsupported
701    BadBurst,
702    /// Band unsupported
703    BadBand,
704    /// Band value unsupported
705    BadBandValue,
706    /// Meter maximum exceeded
707    OutOfMeters,
708    /// Maximum bands exceeded
709    OutOfBands,
710    /// Unknown code
711    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/// Table features failed error codes.
755#[derive(Debug, Clone, Copy, PartialEq, Eq)]
756pub enum TableFeaturesFailedCode {
757    /// Specified table does not exist
758    BadTable,
759    /// Invalid metadata mask
760    BadMetadata,
761    /// Unknown property type
762    BadType,
763    /// Length problem
764    BadLen,
765    /// Unsupported property value
766    BadArgument,
767    /// Permissions error
768    Eperm,
769    /// Unknown code
770    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        // Error type=5 (FLOW_MOD_FAILED), code=1 (TABLE_FULL)
808        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        // Error type=4 (BAD_MATCH), code=9 (BAD_PREREQ)
823        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}