Skip to content

Commit c6377f5

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

File tree

3 files changed

+798
-8
lines changed

3 files changed

+798
-8
lines changed

ovs/action.go

+306-8
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,262 @@ 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+
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+
7221008
// validARPOP indicates if an ARP OP is out of range. It should be in the range
7231009
// 1-4.
7241010
func validARPOP(op uint16) bool {
@@ -742,3 +1028,15 @@ func validVLANVID(vid int) bool {
7421028
func validVLANPCP(pcp int) bool {
7431029
return pcp >= 0 && pcp <= 7
7441030
}
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

Comments
 (0)