@@ -20,6 +20,7 @@ import (
2020 "fmt"
2121 "net"
2222 "strconv"
23+ "strings"
2324)
2425
2526var (
@@ -70,18 +71,28 @@ var (
7071
7172 // errLearnedNil is returned when Learn is called with a nil *LearnedFlow.
7273 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" )
7380)
7481
7582// Action strings in lower case, as those are compared to the lower case letters
7683// in parseAction().
7784const (
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"
8596)
8697
8798// 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 {
120131 return "ovs.Normal()"
121132 case actionStripVLAN :
122133 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()"
123140 default :
124141 return fmt .Sprintf ("// BUG(mdlayher): unimplemented OVS text action: %q" , a .action )
125142 }
@@ -178,6 +195,13 @@ func StripVLAN() Action {
178195 }
179196}
180197
198+ // CTClear clears connection tracking state from the flow
199+ func CTClear () Action {
200+ return & textAction {
201+ action : actionCTClear ,
202+ }
203+ }
204+
181205// printf-style patterns for marshaling and unmarshaling actions.
182206const (
183207 patConnectionTracking = "ct(%s)"
@@ -195,6 +219,12 @@ const (
195219 patResubmitPort = "resubmit:%s"
196220 patResubmitPortTable = "resubmit(%s,%s)"
197221 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)"
198228)
199229
200230// ConnectionTracking sends a packet through the host's connection tracker.
@@ -446,7 +476,7 @@ func (a *outputFieldAction) GoString() string {
446476// applies multipath link selection `algorithm` (with parameter `arg`)
447477// to choose one of `n_links` output links numbered 0 through n_links
448478// 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’’
450480// above.
451481// https://www.openvswitch.org/support/dist-docs/ovs-actions.7.txt
452482func Multipath (fields string , basis int , algorithm string , nlinks int , arg int , dst string ) Action {
@@ -719,6 +749,253 @@ func (a *learnAction) MarshalText() ([]byte, error) {
719749 return bprintf (patLearn , l ), nil
720750}
721751
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+ if a .maxLen != 65535 {
889+ buf .WriteString (fmt .Sprintf ("max_len=%d" , a .maxLen ))
890+ first = false
891+ }
892+ if a .reason != "" {
893+ if ! first {
894+ buf .WriteString ("," )
895+ }
896+ buf .WriteString (fmt .Sprintf ("reason=%s" , a .reason ))
897+ first = false
898+ }
899+ if a .id != 0 {
900+ if ! first {
901+ buf .WriteString ("," )
902+ }
903+ buf .WriteString (fmt .Sprintf ("id=%d" , a .id ))
904+ first = false
905+ }
906+ if a .userdata != "" {
907+ if ! first {
908+ buf .WriteString ("," )
909+ }
910+ buf .WriteString (fmt .Sprintf ("userdata=%s" , a .userdata ))
911+ first = false
912+ }
913+ if a .pause {
914+ if ! first {
915+ buf .WriteString ("," )
916+ }
917+ buf .WriteString ("pause" )
918+ first = false
919+ }
920+ buf .WriteString (")" )
921+ return []byte (buf .String ()), nil
922+ }
923+
924+ // Group outputs the packet to the OpenFlow group
925+ func Group (group int ) Action {
926+ return & groupAction {
927+ group : group ,
928+ }
929+ }
930+
931+ type groupAction struct {
932+ group int
933+ }
934+
935+ // GoString implements Action.
936+ func (a * groupAction ) GoString () string {
937+ return fmt .Sprintf ("ovs.Group(%d)" , a .group )
938+ }
939+
940+ // MarshalText implements Action.
941+ func (a * groupAction ) MarshalText () ([]byte , error ) {
942+ return bprintf (patGroup , a .group ), nil
943+ }
944+
945+ // Bundle action choose a port (a member) from a comma-separated OpenFlow
946+ // port list. After selecting the port, bundle outputs to it
947+ func Bundle (fields string , basis int , algorithm string , members ... int ) Action {
948+ return & bundleAction {
949+ fields : fields ,
950+ basis : basis ,
951+ algorithm : algorithm ,
952+ members : members ,
953+ }
954+ }
955+
956+ type bundleAction struct {
957+ fields string
958+ basis int
959+ algorithm string
960+ members []int
961+ }
962+
963+ // GoString implements Action.
964+ func (a * bundleAction ) GoString () string {
965+ return fmt .Sprintf ("ovs.Bundle(%s,%d,%s,ofport,members:%s)" , a .fields , a .basis , a .algorithm ,
966+ formatIntArr (a .members , ", " ))
967+ }
968+
969+ // MarshalText implements Action.
970+ func (a * bundleAction ) MarshalText () ([]byte , error ) {
971+ return bprintf (patBundle , a .fields , a .basis , a .algorithm ,
972+ formatIntArr (a .members , "," )), nil
973+ }
974+
975+ // DecTTL decrement TTL of IPv4 packet or hop limit of IPv6 packet
976+ func DecTTL (ids ... int ) Action {
977+ return & decTTLAction {
978+ ids : ids ,
979+ }
980+ }
981+
982+ type decTTLAction struct {
983+ ids []int
984+ }
985+
986+ // GoString implements Action.
987+ func (a * decTTLAction ) GoString () string {
988+ return fmt .Sprintf ("ovs.DecTTL(%s)" , formatIntArr (a .ids , ", " ))
989+ }
990+
991+ // MarshalText implements Action.
992+ func (a * decTTLAction ) MarshalText () ([]byte , error ) {
993+ if len (a .ids ) == 0 {
994+ return bprintf (patDecTTL ), nil
995+ }
996+ return bprintf (patDecTTLIds , formatIntArr (a .ids , "," )), nil
997+ }
998+
722999// validARPOP indicates if an ARP OP is out of range. It should be in the range
7231000// 1-4.
7241001func validARPOP (op uint16 ) bool {
@@ -742,3 +1019,15 @@ func validVLANVID(vid int) bool {
7421019func validVLANPCP (pcp int ) bool {
7431020 return pcp >= 0 && pcp <= 7
7441021}
1022+
1023+ // formatIntArr return a comma separate string for an int array
1024+ func formatIntArr (arr []int , sep string ) string {
1025+ var buf strings.Builder
1026+ for idx , i := range arr {
1027+ if idx != 0 {
1028+ buf .WriteString (sep )
1029+ }
1030+ buf .WriteString (strconv .Itoa (i ))
1031+ }
1032+ return buf .String ()
1033+ }
0 commit comments