@@ -30,11 +30,12 @@ const (
3030// Possible errors which may be encountered while marshaling or unmarshaling
3131// a Flow.
3232var (
33- errActionsWithDrop = errors .New ("Flow actions include drop, but multiple actions specified" )
34- errInvalidActions = errors .New ("invalid actions for Flow" )
35- errNoActions = errors .New ("no actions defined for Flow" )
36- errNotEnoughElements = errors .New ("not enough elements for valid Flow" )
37- errPriorityNotFirst = errors .New ("priority field is not first in Flow" )
33+ errActionsWithDrop = errors .New ("Flow actions include drop, but multiple actions specified" )
34+ errInvalidActions = errors .New ("invalid actions for Flow" )
35+ errNoActions = errors .New ("no actions defined for Flow" )
36+ errNotEnoughElements = errors .New ("not enough elements for valid Flow" )
37+ errPriorityNotFirst = errors .New ("priority field is not first in Flow" )
38+ errInvalidLearnedActions = errors .New ("invalid actions for LearnedFlow" )
3839)
3940
4041// A Protocol is an OpenFlow protocol designation accepted by Open vSwitch.
@@ -66,6 +67,20 @@ type Flow struct {
6667 Actions []Action
6768}
6869
70+ // A LearnedFlow is defined as part of the Learn action.
71+ type LearnedFlow struct {
72+ Priority int
73+ InPort int
74+ Matches []Match
75+ Table int
76+ IdleTimeout int
77+ Cookie uint64
78+ Actions []Action
79+
80+ DeleteLearned bool
81+ FinHardTimeout int
82+ }
83+
6984var _ error = & FlowError {}
7085
7186// A FlowError is an error encountered while marshaling or unmarshaling
@@ -105,6 +120,10 @@ const (
105120 hardAge = "hard_age"
106121 idleAge = "idle_age"
107122
123+ // Variables used in LearnedFlows only.
124+ deleteLearned = "delete_learned"
125+ finHardTimeout = "fin_hard_timeout"
126+
108127 portLOCAL = "LOCAL"
109128)
110129
@@ -120,12 +139,12 @@ func (f *Flow) MarshalText() ([]byte, error) {
120139 }
121140 }
122141
123- actions , err := f . marshalActions ()
142+ actions , err := marshalActions (f . Actions )
124143 if err != nil {
125144 return nil , err
126145 }
127146
128- matches , err := f . marshalMatches ()
147+ matches , err := marshalMatches (f . Matches )
129148 if err != nil {
130149 return nil , err
131150 }
@@ -183,6 +202,81 @@ func (f *Flow) MarshalText() ([]byte, error) {
183202 return b , nil
184203}
185204
205+ // MarshalText marshals a LearnedFlow into its textual form.
206+ func (f * LearnedFlow ) MarshalText () ([]byte , error ) {
207+ if len (f .Actions ) == 0 {
208+ return nil , & FlowError {
209+ Err : errNoActions ,
210+ }
211+ }
212+
213+ // A learned flow can have a limited set of actions, namely `load` and `output:field`.
214+ for _ , a := range f .Actions {
215+ switch a .(type ) {
216+ case * loadSetFieldAction :
217+ if a .(* loadSetFieldAction ).typ != actionLoad {
218+ return nil , errInvalidLearnedActions
219+ }
220+ case * outputFieldAction :
221+ default :
222+ return nil , errInvalidLearnedActions
223+ }
224+ }
225+
226+ actions , err := marshalActions (f .Actions )
227+ if err != nil {
228+ return nil , err
229+ }
230+
231+ matches , err := marshalMatches (f .Matches )
232+ if err != nil {
233+ return nil , err
234+ }
235+
236+ b := make ([]byte , len (priorityBytes ))
237+ copy (b , priorityBytes )
238+
239+ b = strconv .AppendInt (b , int64 (f .Priority ), 10 )
240+
241+ if f .InPort != 0 {
242+ b = append (b , "," + inPort + "=" ... )
243+
244+ // Special case, InPortLOCAL is converted to the literal string LOCAL
245+ if f .InPort == PortLOCAL {
246+ b = append (b , portLOCAL ... )
247+ } else {
248+ b = strconv .AppendInt (b , int64 (f .InPort ), 10 )
249+ }
250+ }
251+
252+ if len (matches ) > 0 {
253+ b = append (b , "," + strings .Join (matches , "," )... )
254+ }
255+
256+ b = append (b , "," + table + "=" ... )
257+ b = strconv .AppendInt (b , int64 (f .Table ), 10 )
258+
259+ b = append (b , "," + idleTimeout + "=" ... )
260+ b = strconv .AppendInt (b , int64 (f .IdleTimeout ), 10 )
261+
262+ b = append (b , "," + finHardTimeout + "=" ... )
263+ b = strconv .AppendInt (b , int64 (f .FinHardTimeout ), 10 )
264+
265+ if f .DeleteLearned {
266+ b = append (b , "," + deleteLearned ... )
267+ }
268+
269+ if f .Cookie > 0 {
270+ // Hexadecimal cookies are much easier to read.
271+ b = append (b , "," + cookie + "=" ... )
272+ b = append (b , paddedHexUint64 (f .Cookie )... )
273+ }
274+
275+ b = append (b , "," + strings .Join (actions , "," )... )
276+
277+ return b , nil
278+ }
279+
186280// UnmarshalText unmarshals flow text into a Flow.
187281func (f * Flow ) UnmarshalText (b []byte ) error {
188282 // Make a copy per documentation for encoding.TextUnmarshaler.
@@ -339,28 +433,28 @@ func (f *Flow) MatchFlow() *MatchFlow {
339433 }
340434}
341435
342- // marshalActions marshals all Actions in a Flow to their text form.
343- func ( f * Flow ) marshalActions () ([]string , error ) {
344- fns := make ([]func () ([]byte , error ), 0 , len (f . Actions ))
345- for _ , fn := range f . Actions {
436+ // marshalActions marshals all provided Actions to their text form.
437+ func marshalActions (aa [] Action ) ([]string , error ) {
438+ fns := make ([]func () ([]byte , error ), 0 , len (aa ))
439+ for _ , fn := range aa {
346440 fns = append (fns , fn .MarshalText )
347441 }
348442
349- return f . marshalFunctions (fns )
443+ return marshalFunctions (fns )
350444}
351445
352- // marshalMatches marshals all Matches in a Flow to their text form.
353- func ( f * Flow ) marshalMatches () ([]string , error ) {
354- fns := make ([]func () ([]byte , error ), 0 , len (f . Matches ))
355- for _ , fn := range f . Matches {
446+ // marshalMatches marshals all provided Matches to their text form.
447+ func marshalMatches (mm [] Match ) ([]string , error ) {
448+ fns := make ([]func () ([]byte , error ), 0 , len (mm ))
449+ for _ , fn := range mm {
356450 fns = append (fns , fn .MarshalText )
357451 }
358452
359- return f . marshalFunctions (fns )
453+ return marshalFunctions (fns )
360454}
361455
362456// marshalFunctions marshals a slice of functions to their text form.
363- func ( f * Flow ) marshalFunctions (fns []func () ([]byte , error )) ([]string , error ) {
457+ func marshalFunctions (fns []func () ([]byte , error )) ([]string , error ) {
364458 out := make ([]string , 0 , len (fns ))
365459 for _ , fn := range fns {
366460 o , err := fn ()
0 commit comments