Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

redesign ethdev/flow #27

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions app/test-sniffer/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ func rssEthVlanIPv4(pid ethdev.Port, conf *ethdev.RssConf) (*flow.Flow, error) {
attr := &flow.Attr{Ingress: true}

pattern := []flow.Item{
{Spec: flow.ItemTypeEth}, // Ethernet
{Spec: flow.ItemTypeVlan}, // VLAN
{Spec: flow.ItemTypeIPv4}, // IPv4
{Spec: &flow.ItemEth{}}, // Ethernet
{Spec: &flow.ItemVlan{}}, // VLAN
{Spec: &flow.ItemIPv4{}}, // IPv4
}

actions := []flow.Action{
Expand All @@ -83,9 +83,9 @@ func mlxRssEthVlanIPv4(pid ethdev.Port, conf *ethdev.RssConf) (*flow.Flow, error
attr := &flow.Attr{Ingress: true}

pattern := []flow.Item{
{Spec: flow.ItemTypeEth}, // Ethernet
{Spec: flow.ItemTypeVlan}, // VLAN
{Spec: flow.ItemTypeIPv4}, // IPv4
{Spec: &flow.ItemEth{}}, // Ethernet
{Spec: &flow.ItemVlan{}}, // VLAN
{Spec: &flow.ItemIPv4{}}, // IPv4
}

var info ethdev.DevInfo
Expand Down
24 changes: 6 additions & 18 deletions ethdev/flow/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,22 @@ package flow
#include <rte_flow.h>
*/
import "C"
import "unsafe"
import (
"github.com/yerden/go-dpdk/common"
)

// ActionType is the rte_flow_action type.
type ActionType uint32

// Reload implements Action interface.
func (t ActionType) Reload() {}

// Pointer implements Action interface.
func (t ActionType) Pointer() unsafe.Pointer { return nil }

// Type implements Action interface.
func (t ActionType) Type() ActionType { return t }

// Action is the definition of a single action.
//
// A list of actions is terminated by a END action.
//
// For simple actions without a configuration object, conf remains
// NULL.
type Action interface {
// Pointer returns a valid C pointer to underlying struct.
Pointer() unsafe.Pointer

// Reload is used to apply changes so that the underlying struct
// reflects the up-to-date configuration.
Reload()
common.Transformer

// Type returns implemented rte_flow_action_* struct.
Type() ActionType
// ActionType returns implemented rte_flow_action_* struct.
ActionType() ActionType
}
21 changes: 11 additions & 10 deletions ethdev/flow/action_queue.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,28 @@ package flow
*/
import "C"
import (
"runtime"
"unsafe"

"github.com/yerden/go-dpdk/common"
)

var _ Action = (*ActionQueue)(nil)

// ActionQueue implements Action which assigns packets to a given
// queue index.
type ActionQueue struct {
cPointer
Index uint16
}

// Reload implements Action interface.
func (action *ActionQueue) Reload() {
cptr := (*C.struct_rte_flow_action_queue)(action.createOrRet(C.sizeof_struct_rte_flow_action_queue))

cptr.index = C.uint16_t(action.Index)
runtime.SetFinalizer(action, (*ActionQueue).free)
// Transform implements Action interface.
func (action *ActionQueue) Transform(alloc common.Allocator) (unsafe.Pointer, func(unsafe.Pointer)) {
s := &C.struct_rte_flow_action_queue{
index: C.ushort(action.Index),
}
return common.TransformPOD(alloc, s)
}

// Type implements Action interface.
func (action *ActionQueue) Type() ActionType {
// ActionType implements Action interface.
func (action *ActionQueue) ActionType() ActionType {
return ActionTypeQueue
}
59 changes: 21 additions & 38 deletions ethdev/flow/action_rss.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ package flow
*/
import "C"
import (
"runtime"
"unsafe"

"github.com/yerden/go-dpdk/common"
)

var _ Action = (*ActionRSS)(nil)
Expand All @@ -34,61 +35,43 @@ type ActionRSS struct {
Key []byte
Level uint32
Types uint64

cptr *C.struct_rte_flow_action_rss
}

func (action *ActionRSS) free() {
cptr := action.cptr
C.free(unsafe.Pointer(cptr.key))
C.free(unsafe.Pointer(cptr.queue))
C.free(unsafe.Pointer(cptr))
}

// Reload implements Action interface.
func (action *ActionRSS) Reload() {
// allocate if needed
cptr := action.cptr
if cptr == nil {
cptr = (*C.struct_rte_flow_action_rss)(C.malloc(C.sizeof_struct_rte_flow_action_rss))
*cptr = C.struct_rte_flow_action_rss{}
action.cptr = cptr
}
// Transform implements Action interface.
func (action *ActionRSS) Transform(alloc common.Allocator) (unsafe.Pointer, func(unsafe.Pointer)) {
cptr := (*C.struct_rte_flow_action_rss)(alloc.Malloc(C.sizeof_struct_rte_flow_action_rss))
*cptr = C.struct_rte_flow_action_rss{}

// set queues
if len(action.Queues) > 0 {
sz := C.size_t(len(action.Queues)) * C.size_t(unsafe.Sizeof(action.Queues[0]))
cQueues := C.malloc(sz)
C.memcpy(cQueues, unsafe.Pointer(&action.Queues[0]), sz)
C.free(unsafe.Pointer(cptr.queue))
var x *C.uint16_t
common.CallocT(alloc, &x, len(action.Queues))
queues := unsafe.Slice(x, len(action.Queues))
for i := range queues {
queues[i] = C.uint16_t(action.Queues[i])
}
cptr.queue_num = C.uint32_t(len(action.Queues))
cptr.queue = (*C.uint16_t)(cQueues)
}

// set key
if len(action.Key) > 0 {
sz := C.size_t(len(action.Key))
cKey := C.malloc(sz)
C.memcpy(cKey, unsafe.Pointer(&action.Key[0]), sz)
C.free(unsafe.Pointer(cptr.key))
cptr.key_len = C.uint32_t(len(action.Key))
cptr.key = (*C.uint8_t)(cKey)
cptr.key = (*C.uchar)(common.CBytes(alloc, action.Key))
}

cptr.level = C.uint32_t(action.Level)
cptr.types = C.uint64_t(action.Types)
cptr._func = uint32(action.Func)

runtime.SetFinalizer(action, nil)
runtime.SetFinalizer(action, (*ActionRSS).free)
}

// Pointer implements Action interface.
func (action *ActionRSS) Pointer() unsafe.Pointer {
return unsafe.Pointer(action.cptr)
return unsafe.Pointer(cptr), func(p unsafe.Pointer) {
cptr = (*C.struct_rte_flow_action_rss)(p)
alloc.Free(unsafe.Pointer(cptr.key))
alloc.Free(unsafe.Pointer(cptr.queue))
alloc.Free(p)
}
}

// Type implements Action interface.
func (action *ActionRSS) Type() ActionType {
// ActionType implements Action interface.
func (action *ActionRSS) ActionType() ActionType {
return ActionTypeRss
}
103 changes: 55 additions & 48 deletions ethdev/flow/flow.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ package flow
import "C"

import (
"runtime"

"github.com/yerden/go-dpdk/common"
"github.com/yerden/go-dpdk/ethdev"
)
Expand All @@ -23,40 +21,54 @@ const _ uintptr = -uintptr(ActionTypeEnd)
// Flow is the opaque flow handle.
type Flow C.struct_rte_flow

// allocate c-style list of rte_flow_item's.
func cPattern(pattern []Item) []C.struct_rte_flow_item {
pat := make([]C.struct_rte_flow_item, len(pattern)+1)
type cArgs struct {
pid C.ushort
attr C.struct_rte_flow_attr
pat *C.struct_rte_flow_item
act *C.struct_rte_flow_action
e *C.struct_rte_flow_error
}

func doFancy(port ethdev.Port, attr *Attr, pattern []Item, actions []Action, flowErr *Error, fn func(*cArgs)) {
alloc := common.NewAllocatorSession(&common.StdAlloc{})
defer alloc.Flush()

// patterns
var pat []C.struct_rte_flow_item
for i := range pattern {
typ := pattern[i].Spec.Type()
pat[i]._type = uint32(typ)
pattern[i].Spec.Reload()
pat[i].spec = pattern[i].Spec.Pointer()
if item := pattern[i].Mask; item != nil {
item.Reload()
pat[i].mask = item.Pointer()
}
if item := pattern[i].Last; item != nil {
item.Reload()
pat[i].last = item.Pointer()
}
p := &pattern[i]
cPat := C.struct_rte_flow_item{}
cPat._type = uint32(p.Spec.ItemType())
cPat.spec, _ = pattern[i].Spec.Transform(alloc)
cPat.last, _ = pattern[i].Last.Transform(alloc)
cPat.mask, _ = pattern[i].Mask.Transform(alloc)
pat = append(pat, cPat)
}

return pat
}
// patterns finalizer
pat = append(pat, C.struct_rte_flow_item{})

// allocate c-style list of rte_flow_action's.
func cActions(actions []Action) []C.struct_rte_flow_action {
act := make([]C.struct_rte_flow_action, len(actions)+1)
// actions
var act []C.struct_rte_flow_action
for _, p := range actions {
cAction := C.struct_rte_flow_action{}
cAction._type = uint32(p.ActionType())
cAction.conf, _ = p.Transform(alloc)
act = append(act, cAction)
}

// actions finalizer
act = append(act, C.struct_rte_flow_action{})

for i := range actions {
typ := actions[i].Type()
act[i]._type = uint32(typ)
actions[i].Reload()
act[i].conf = actions[i].Pointer()
args := &cArgs{
pid: C.ushort(port),
attr: attr.cvtAttr(),
pat: &pat[0],
act: &act[0],
e: (*C.struct_rte_flow_error)(flowErr),
}

return act
fn(args)
}

// Create a flow rule on a given port.
Expand All @@ -71,18 +83,15 @@ func cActions(actions []Action) []C.struct_rte_flow_action {
// Returns a valid handle in case of success, NULL otherwise and
// rte_errno is set to the positive version of one of the error codes
// defined for rte_flow_validate().
func Create(port ethdev.Port, attr *Attr, pattern []Item, actions []Action, flowErr *Error) (*Flow, error) {
pat := cPattern(pattern)
act := cActions(actions)
cAttr := attr.cvtAttr()
f := C.rte_flow_create(C.ushort(port), &cAttr, &pat[0], &act[0], (*C.struct_rte_flow_error)(flowErr))
runtime.KeepAlive(pattern)
runtime.KeepAlive(actions)
if f == nil {
return nil, common.RteErrno()
}

return (*Flow)(f), nil
func Create(port ethdev.Port, attr *Attr, pattern []Item, actions []Action, flowErr *Error) (f *Flow, err error) {
doFancy(port, attr, pattern, actions, flowErr, func(args *cArgs) {
if p := C.rte_flow_create(args.pid, &args.attr, args.pat, args.act, args.e); p != nil {
f = (*Flow)(p)
} else {
err = common.RteErrno()
}
})
return
}

// Validate checks whether a flow rule can be created on a given port.
Expand All @@ -99,14 +108,12 @@ func Create(port ethdev.Port, attr *Attr, pattern []Item, actions []Action, flow
// made in the meantime and no device parameter affecting flow rules
// in any way are modified, due to possible collisions or resource
// limitations (although in such cases EINVAL should not be returned).
func Validate(port ethdev.Port, attr *Attr, pattern []Item, actions []Action, flowErr *Error) error {
pat := cPattern(pattern)
act := cActions(actions)
cAttr := attr.cvtAttr()
ret := C.rte_flow_validate(C.ushort(port), &cAttr, &pat[0], &act[0], (*C.struct_rte_flow_error)(flowErr))
runtime.KeepAlive(pattern)
runtime.KeepAlive(actions)
return common.IntToErr(ret)
func Validate(port ethdev.Port, attr *Attr, pattern []Item, actions []Action, flowErr *Error) (err error) {
doFancy(port, attr, pattern, actions, flowErr, func(args *cArgs) {
rc := C.rte_flow_validate(args.pid, &args.attr, args.pat, args.act, args.e)
err = common.IntErr(int64(rc))
})
return
}

// Destroy a flow rule on a given port.
Expand Down
10 changes: 0 additions & 10 deletions ethdev/flow/flow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,3 @@ func assert(t testing.TB, expected bool, args ...interface{}) {
t.Fatal(args...)
}
}

func TestCPattern(t *testing.T) {
pattern := []Item{
{Spec: &ItemIPv4{}, Mask: &ItemIPv4{}},
}

pat := cPattern(pattern)
assert(t, pat != nil)

}
Loading