@@ -20,6 +20,7 @@ import (
20
20
"fmt"
21
21
"net"
22
22
"strconv"
23
+ "strings"
23
24
)
24
25
25
26
var (
@@ -70,18 +71,28 @@ var (
70
71
71
72
// errLearnedNil is returned when Learn is called with a nil *LearnedFlow.
72
73
errLearnedNil = errors .New ("learned flow for action learn is nil" )
74
+
75
+ // errPopFieldEmpty is returned when Pop is called with field set to the empty string
76
+ errPopFieldEmpty = errors .New ("field for action pop (pop:field syntax) is empty" )
77
+
78
+ // errPushFieldEmpty is returned when Push is called with field set to the empty string
79
+ errPushFieldEmpty = errors .New ("field for action push (push:field syntax) is empty" )
73
80
)
74
81
75
82
// Action strings in lower case, as those are compared to the lower case letters
76
83
// in parseAction().
77
84
const (
78
- actionAll = "all"
79
- actionDrop = "drop"
80
- actionFlood = "flood"
81
- actionInPort = "in_port"
82
- actionLocal = "local"
83
- actionNormal = "normal"
84
- actionStripVLAN = "strip_vlan"
85
+ actionAll = "all"
86
+ actionDrop = "drop"
87
+ actionFlood = "flood"
88
+ actionInPort = "in_port"
89
+ actionLocal = "local"
90
+ actionNormal = "normal"
91
+ actionStripVLAN = "strip_vlan"
92
+ actionDecTTL = "dec_ttl"
93
+ actionDecTTLNoParam = "dec_ttl()"
94
+ actionCTClear = "ct_clear"
95
+ actionController = "controller"
85
96
)
86
97
87
98
// An Action is a type which can be marshaled into an OpenFlow action. Actions can be
@@ -120,6 +131,12 @@ func (a *textAction) GoString() string {
120
131
return "ovs.Normal()"
121
132
case actionStripVLAN :
122
133
return "ovs.StripVLAN()"
134
+ case actionDecTTL , actionDecTTLNoParam :
135
+ return "ovs.DecTTL()"
136
+ case actionCTClear :
137
+ return "ovs.CTClear()"
138
+ case actionController :
139
+ return "ovs.Controller()"
123
140
default :
124
141
return fmt .Sprintf ("// BUG(mdlayher): unimplemented OVS text action: %q" , a .action )
125
142
}
@@ -178,6 +195,13 @@ func StripVLAN() Action {
178
195
}
179
196
}
180
197
198
+ // CTClear clears connection tracking state from the flow
199
+ func CTClear () Action {
200
+ return & textAction {
201
+ action : actionCTClear ,
202
+ }
203
+ }
204
+
181
205
// printf-style patterns for marshaling and unmarshaling actions.
182
206
const (
183
207
patConnectionTracking = "ct(%s)"
@@ -195,6 +219,12 @@ const (
195
219
patResubmitPort = "resubmit:%s"
196
220
patResubmitPortTable = "resubmit(%s,%s)"
197
221
patLearn = "learn(%s)"
222
+ patPush = "push:%s"
223
+ patPop = "pop:%s"
224
+ patGroup = "group:%d"
225
+ patBundle = "bundle(%s,%d,%s,ofport,members:%s)"
226
+ patDecTTL = "dec_ttl"
227
+ patDecTTLIds = "dec_ttl(%s)"
198
228
)
199
229
200
230
// ConnectionTracking sends a packet through the host's connection tracker.
@@ -446,7 +476,7 @@ func (a *outputFieldAction) GoString() string {
446
476
// applies multipath link selection `algorithm` (with parameter `arg`)
447
477
// to choose one of `n_links` output links numbered 0 through n_links
448
478
// minus 1, and stores the link into `dst`, which must be a field or
449
- // subfield in the syntax described under `` Field Specifications’’
479
+ // subfield in the syntax described under “ Field Specifications’’
450
480
// above.
451
481
// https://www.openvswitch.org/support/dist-docs/ovs-actions.7.txt
452
482
func Multipath (fields string , basis int , algorithm string , nlinks int , arg int , dst string ) Action {
@@ -719,6 +749,262 @@ func (a *learnAction) MarshalText() ([]byte, error) {
719
749
return bprintf (patLearn , l ), nil
720
750
}
721
751
752
+ // Push action pushes src on a general-purpose stack
753
+ // If either string is empty, an error is returned.
754
+ func Push (field string ) Action {
755
+ return & pushAction {
756
+ field : field ,
757
+ }
758
+ }
759
+
760
+ type pushAction struct {
761
+ field string
762
+ }
763
+
764
+ // GoString implements Action.
765
+ func (a * pushAction ) GoString () string {
766
+ return fmt .Sprintf ("ovs.Push(%#v)" , a .field )
767
+ }
768
+
769
+ // MarshalText implements Action.
770
+ func (a * pushAction ) MarshalText () ([]byte , error ) {
771
+ if a .field == "" {
772
+ return nil , errPushFieldEmpty
773
+ }
774
+
775
+ return bprintf (patPush , a .field ), nil
776
+ }
777
+
778
+ // Pop action pops an entry off the stack into dst
779
+ // If either string is empty, an error is returned.
780
+ func Pop (field string ) Action {
781
+ return & popAction {
782
+ field : field ,
783
+ }
784
+ }
785
+
786
+ type popAction struct {
787
+ field string
788
+ }
789
+
790
+ // GoString implements Action.
791
+ func (a * popAction ) GoString () string {
792
+ return fmt .Sprintf ("ovs.Pop(%#v)" , a .field )
793
+ }
794
+
795
+ // MarshalText implements Action.
796
+ func (a * popAction ) MarshalText () ([]byte , error ) {
797
+ if a .field == "" {
798
+ return nil , errPopFieldEmpty
799
+ }
800
+
801
+ return bprintf (patPop , a .field ), nil
802
+ }
803
+
804
+ // Controller sends the packet and its metadata to an OpenFlow controller or controllers
805
+ // encapsulated in an OpenFlow packet-in message overwrites the specified field with the specified value.
806
+ func Controller (maxLen int , reason string , id int , userdata string , pause bool ) Action {
807
+ if maxLen == 0 {
808
+ maxLen = 65535
809
+ }
810
+ return & controllerAction {
811
+ maxLen : maxLen ,
812
+ reason : reason ,
813
+ id : id ,
814
+ userdata : userdata ,
815
+ pause : pause ,
816
+ }
817
+ }
818
+
819
+ type controllerAction struct {
820
+ maxLen int
821
+ reason string
822
+ id int
823
+ userdata string
824
+ pause bool
825
+ }
826
+
827
+ // GoString implements Action.
828
+ func (a * controllerAction ) GoString () string {
829
+
830
+ var buf strings.Builder
831
+ buf .WriteString ("ovs.Controller(" )
832
+ first := true
833
+ if a .maxLen != 65535 {
834
+ buf .WriteString (fmt .Sprintf ("max_len=%d" , a .maxLen ))
835
+ first = false
836
+ }
837
+ if a .reason != "" {
838
+ if ! first {
839
+ buf .WriteString (", " )
840
+ }
841
+ buf .WriteString (fmt .Sprintf ("reason=%s" , a .reason ))
842
+ first = false
843
+ }
844
+ if a .id != 0 {
845
+ if ! first {
846
+ buf .WriteString (", " )
847
+ }
848
+ buf .WriteString (fmt .Sprintf ("id=%d" , a .id ))
849
+ first = false
850
+ }
851
+ if a .userdata != "" {
852
+ if ! first {
853
+ buf .WriteString (", " )
854
+ }
855
+ buf .WriteString (fmt .Sprintf ("userdata=%s" , a .userdata ))
856
+ first = false
857
+ }
858
+ if a .pause {
859
+ if ! first {
860
+ buf .WriteString (", " )
861
+ }
862
+ buf .WriteString ("pause" )
863
+ first = false
864
+ }
865
+ buf .WriteString (")" )
866
+ return buf .String ()
867
+ }
868
+
869
+ func (a * controllerAction ) IsZero () bool {
870
+ return a .maxLen == 65535 && a .reason == "" && a .id == 0 && a .userdata == "" && ! a .pause
871
+ }
872
+
873
+ func (a * controllerAction ) OnlyMaxLen () bool {
874
+ return a .maxLen != 65535 && a .reason == "" && a .id == 0 && a .userdata == "" && ! a .pause
875
+ }
876
+
877
+ // MarshalText implements Action.
878
+ func (a * controllerAction ) MarshalText () ([]byte , error ) {
879
+ if a .IsZero () {
880
+ return bprintf ("controller" ), nil
881
+ }
882
+ if a .OnlyMaxLen () {
883
+ return bprintf ("controller:%d" , a .maxLen ), nil
884
+ }
885
+ var buf strings.Builder
886
+ buf .WriteString ("controller(" )
887
+ first := true
888
+ onlyMaxLen := false
889
+ if a .maxLen != 65535 {
890
+ buf .WriteString (fmt .Sprintf ("max_len=%d" , a .maxLen ))
891
+ first = false
892
+ onlyMaxLen = true
893
+ }
894
+ if a .reason != "" {
895
+ if ! first {
896
+ buf .WriteString ("," )
897
+ }
898
+ buf .WriteString (fmt .Sprintf ("reason=%s" , a .reason ))
899
+ first = false
900
+ onlyMaxLen = false
901
+ }
902
+ if a .id != 0 {
903
+ if ! first {
904
+ buf .WriteString ("," )
905
+ }
906
+ buf .WriteString (fmt .Sprintf ("id=%d" , a .id ))
907
+ first = false
908
+ onlyMaxLen = false
909
+ }
910
+ if a .userdata != "" {
911
+ if ! first {
912
+ buf .WriteString ("," )
913
+ }
914
+ buf .WriteString (fmt .Sprintf ("userdata=%s" , a .userdata ))
915
+ first = false
916
+ onlyMaxLen = false
917
+ }
918
+ if a .pause {
919
+ if ! first {
920
+ buf .WriteString ("," )
921
+ }
922
+ buf .WriteString ("pause" )
923
+ first = false
924
+ onlyMaxLen = false
925
+ }
926
+ if onlyMaxLen {
927
+ return bprintf ("controller:%d" , a .maxLen ), nil
928
+ }
929
+ buf .WriteString (")" )
930
+ return []byte (buf .String ()), nil
931
+ }
932
+
933
+ // Group outputs the packet to the OpenFlow group
934
+ func Group (group int ) Action {
935
+ return & groupAction {
936
+ group : group ,
937
+ }
938
+ }
939
+
940
+ type groupAction struct {
941
+ group int
942
+ }
943
+
944
+ // GoString implements Action.
945
+ func (a * groupAction ) GoString () string {
946
+ return fmt .Sprintf ("ovs.Group(%d)" , a .group )
947
+ }
948
+
949
+ // MarshalText implements Action.
950
+ func (a * groupAction ) MarshalText () ([]byte , error ) {
951
+ return bprintf (patGroup , a .group ), nil
952
+ }
953
+
954
+ // Bundle action choose a port (a member) from a comma-separated OpenFlow
955
+ // port list. After selecting the port, bundle outputs to it
956
+ func Bundle (fields string , basis int , algorithm string , members ... int ) Action {
957
+ return & bundleAction {
958
+ fields : fields ,
959
+ basis : basis ,
960
+ algorithm : algorithm ,
961
+ members : members ,
962
+ }
963
+ }
964
+
965
+ type bundleAction struct {
966
+ fields string
967
+ basis int
968
+ algorithm string
969
+ members []int
970
+ }
971
+
972
+ // GoString implements Action.
973
+ func (a * bundleAction ) GoString () string {
974
+ return fmt .Sprintf ("ovs.Bundle(%s,%d,%s,ofport,members:%s)" , a .fields , a .basis , a .algorithm ,
975
+ formatIntArr (a .members , ", " ))
976
+ }
977
+
978
+ // MarshalText implements Action.
979
+ func (a * bundleAction ) MarshalText () ([]byte , error ) {
980
+ return bprintf (patBundle , a .fields , a .basis , a .algorithm ,
981
+ formatIntArr (a .members , "," )), nil
982
+ }
983
+
984
+ // DecTTL decrement TTL of IPv4 packet or hop limit of IPv6 packet
985
+ func DecTTL (ids ... int ) Action {
986
+ return & decTTLAction {
987
+ ids : ids ,
988
+ }
989
+ }
990
+
991
+ type decTTLAction struct {
992
+ ids []int
993
+ }
994
+
995
+ // GoString implements Action.
996
+ func (a * decTTLAction ) GoString () string {
997
+ return fmt .Sprintf ("ovs.DecTTL(%s)" , formatIntArr (a .ids , ", " ))
998
+ }
999
+
1000
+ // MarshalText implements Action.
1001
+ func (a * decTTLAction ) MarshalText () ([]byte , error ) {
1002
+ if len (a .ids ) == 0 {
1003
+ return bprintf (patDecTTL ), nil
1004
+ }
1005
+ return bprintf (patDecTTLIds , formatIntArr (a .ids , "," )), nil
1006
+ }
1007
+
722
1008
// validARPOP indicates if an ARP OP is out of range. It should be in the range
723
1009
// 1-4.
724
1010
func validARPOP (op uint16 ) bool {
@@ -742,3 +1028,15 @@ func validVLANVID(vid int) bool {
742
1028
func validVLANPCP (pcp int ) bool {
743
1029
return pcp >= 0 && pcp <= 7
744
1030
}
1031
+
1032
+ // formatIntArr return a comma separate string for an int array
1033
+ func formatIntArr (arr []int , sep string ) string {
1034
+ var buf strings.Builder
1035
+ for idx , i := range arr {
1036
+ if idx != 0 {
1037
+ buf .WriteString (sep )
1038
+ }
1039
+ buf .WriteString (strconv .Itoa (i ))
1040
+ }
1041
+ return buf .String ()
1042
+ }
0 commit comments