Skip to content

Commit 2d2fd76

Browse files
committed
support pop,push,dec_ttl,controller,ct_clear,group,bundle action
1 parent 977d985 commit 2d2fd76

File tree

3 files changed

+789
-8
lines changed

3 files changed

+789
-8
lines changed

ovs/action.go

Lines changed: 297 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"fmt"
2121
"net"
2222
"strconv"
23+
"strings"
2324
)
2425

2526
var (
@@ -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().
7784
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"
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.
182206
const (
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
452482
func 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.
7241001
func validARPOP(op uint16) bool {
@@ -742,3 +1019,15 @@ func validVLANVID(vid int) bool {
7421019
func 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

Comments
 (0)