@@ -30,11 +30,12 @@ const (
30
30
// Possible errors which may be encountered while marshaling or unmarshaling
31
31
// a Flow.
32
32
var (
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" )
38
39
)
39
40
40
41
// A Protocol is an OpenFlow protocol designation accepted by Open vSwitch.
@@ -66,6 +67,20 @@ type Flow struct {
66
67
Actions []Action
67
68
}
68
69
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
+
69
84
var _ error = & FlowError {}
70
85
71
86
// A FlowError is an error encountered while marshaling or unmarshaling
@@ -105,6 +120,10 @@ const (
105
120
hardAge = "hard_age"
106
121
idleAge = "idle_age"
107
122
123
+ // Variables used in LearnedFlows only.
124
+ deleteLearned = "delete_learned"
125
+ finHardTimeout = "fin_hard_timeout"
126
+
108
127
portLOCAL = "LOCAL"
109
128
)
110
129
@@ -120,12 +139,12 @@ func (f *Flow) MarshalText() ([]byte, error) {
120
139
}
121
140
}
122
141
123
- actions , err := f . marshalActions ()
142
+ actions , err := marshalActions (f . Actions )
124
143
if err != nil {
125
144
return nil , err
126
145
}
127
146
128
- matches , err := f . marshalMatches ()
147
+ matches , err := marshalMatches (f . Matches )
129
148
if err != nil {
130
149
return nil , err
131
150
}
@@ -183,6 +202,81 @@ func (f *Flow) MarshalText() ([]byte, error) {
183
202
return b , nil
184
203
}
185
204
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
+
186
280
// UnmarshalText unmarshals flow text into a Flow.
187
281
func (f * Flow ) UnmarshalText (b []byte ) error {
188
282
// Make a copy per documentation for encoding.TextUnmarshaler.
@@ -339,28 +433,28 @@ func (f *Flow) MatchFlow() *MatchFlow {
339
433
}
340
434
}
341
435
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 {
346
440
fns = append (fns , fn .MarshalText )
347
441
}
348
442
349
- return f . marshalFunctions (fns )
443
+ return marshalFunctions (fns )
350
444
}
351
445
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 {
356
450
fns = append (fns , fn .MarshalText )
357
451
}
358
452
359
- return f . marshalFunctions (fns )
453
+ return marshalFunctions (fns )
360
454
}
361
455
362
456
// 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 ) {
364
458
out := make ([]string , 0 , len (fns ))
365
459
for _ , fn := range fns {
366
460
o , err := fn ()
0 commit comments