Skip to content

Commit

Permalink
Support for OVS_FLOW_ATTR_CLEAR and OVS_FLOW_ATTR_USED
Browse files Browse the repository at this point in the history
  • Loading branch information
dpw committed Sep 14, 2015
1 parent 89548ce commit e56f0e7
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 40 deletions.
6 changes: 3 additions & 3 deletions odp/dpif_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,12 +308,12 @@ func TestCreateFlow(t *testing.T) {
t.Fatal(err)
}

err = dp.DeleteFlow(f)
err = dp.DeleteFlow(f.FlowKeys)
if err != nil {
t.Fatal(err)
}

err = dp.DeleteFlow(f)
err = dp.DeleteFlow(f.FlowKeys)
if !IsNoSuchFlowError(err) {
t.Fatal()
}
Expand Down Expand Up @@ -380,7 +380,7 @@ func TestEnumerateFlows(t *testing.T) {
}

for _, eflow := range eflows {
err = dp.DeleteFlow(eflow.FlowSpec)
err = dp.DeleteFlow(eflow.FlowKeys)
if err != nil {
t.Fatal(err)
}
Expand Down
91 changes: 57 additions & 34 deletions odp/flow.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,39 @@ func (a FlowKeys) Equals(b FlowKeys) bool {
return true
}

func (fks FlowKeys) toNlAttrs(msg *NlMsgBuilder) {
// The ethernet flow key is mandatory, even if it is
// completely wildcarded.
var defaultEthernetFlowKey FlowKey
if fks[OVS_KEY_ATTR_ETHERNET] == nil {
defaultEthernetFlowKey = NewEthernetFlowKey()
}

msg.PutNestedAttrs(OVS_FLOW_ATTR_KEY, func() {
for _, k := range fks {
if !k.Ignored() {
k.putKeyNlAttr(msg)
}
}

if defaultEthernetFlowKey != nil {
defaultEthernetFlowKey.putKeyNlAttr(msg)
}
})

msg.PutNestedAttrs(OVS_FLOW_ATTR_MASK, func() {
for _, k := range fks {
if !k.Ignored() {
k.putMaskNlAttr(msg)
}
}

if defaultEthernetFlowKey != nil {
defaultEthernetFlowKey.putMaskNlAttr(msg)
}
})
}

// A FlowKeyParser describes how to parse a flow key of a particular
// type from a netlnk message
type FlowKeyParser struct {
Expand Down Expand Up @@ -1040,38 +1073,7 @@ func (f *FlowSpec) AddActions(as []Action) {
}

func (f FlowSpec) toNlAttrs(msg *NlMsgBuilder) {
// The ethernet flow key is mandatory, even if it is
// completely wildcarded.
var defaultEthernetFlowKey FlowKey
if f.FlowKeys[OVS_KEY_ATTR_ETHERNET] == nil {
defaultEthernetFlowKey = NewEthernetFlowKey()
}

msg.PutNestedAttrs(OVS_FLOW_ATTR_KEY, func() {
for _, k := range f.FlowKeys {
if !k.Ignored() {
k.putKeyNlAttr(msg)
}
}

if defaultEthernetFlowKey != nil {
defaultEthernetFlowKey.putKeyNlAttr(msg)
}
})

msg.PutNestedAttrs(OVS_FLOW_ATTR_MASK, func() {
for _, k := range f.FlowKeys {
if !k.Ignored() {
k.putMaskNlAttr(msg)
}
}

if defaultEthernetFlowKey != nil {
defaultEthernetFlowKey.putMaskNlAttr(msg)
}
})

// ACTIONS is required
f.FlowKeys.toNlAttrs(msg)
msg.PutNestedAttrs(OVS_FLOW_ATTR_ACTIONS, func() {
for _, a := range f.Actions {
a.toNlAttr(msg)
Expand Down Expand Up @@ -1155,13 +1157,26 @@ func (dp DatapathHandle) CreateFlow(f FlowSpec) error {
return err
}

func (dp DatapathHandle) DeleteFlow(f FlowSpec) error {
func (dp DatapathHandle) DeleteFlow(fks FlowKeys) error {
dpif := dp.dpif

req := NewNlMsgBuilder(RequestFlags, dpif.families[FLOW].id)
req.PutGenlMsghdr(OVS_FLOW_CMD_DEL, OVS_FLOW_VERSION)
req.putOvsHeader(dp.ifindex)
f.toNlAttrs(req)
fks.toNlAttrs(req)

_, err := dpif.sock.Request(req)
return err
}

func (dp DatapathHandle) ClearFlow(fks FlowKeys) error {
dpif := dp.dpif

req := NewNlMsgBuilder(RequestFlags, dpif.families[FLOW].id)
req.PutGenlMsghdr(OVS_FLOW_CMD_SET, OVS_FLOW_VERSION)
req.putOvsHeader(dp.ifindex)
fks.toNlAttrs(req)
req.PutEmptyAttr(OVS_FLOW_ATTR_CLEAR)

_, err := dpif.sock.Request(req)
return err
Expand All @@ -1175,6 +1190,7 @@ type FlowInfo struct {
FlowSpec
Packets uint64
Bytes uint64
Used uint64
}

func parseFlowInfo(attrs Attrs) (fi FlowInfo, err error) {
Expand All @@ -1195,6 +1211,13 @@ func parseFlowInfo(attrs Attrs) (fi FlowInfo, err error) {
fi.Bytes = stats.NBytes
}

used, usedPresent, err := attrs.GetOptionalUint64(OVS_FLOW_ATTR_USED)
if err != nil {
return
} else if usedPresent {
fi.Used = used
}

return
}

Expand Down
22 changes: 22 additions & 0 deletions odp/netlink.go
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,28 @@ func (attrs Attrs) GetUint32(typ uint16) (uint32, error) {
return *uint32At(val, 0), nil
}

func (attrs Attrs) getUint64(typ uint16, optional bool) (uint64, bool, error) {
val, err := attrs.Get(typ, optional)
if err != nil || val == nil {
return 0, false, err
}

if len(val) != 8 {
return 0, false, fmt.Errorf("uint64 attribute %d has wrong length (%d bytes)", typ, len(val))
}

return *uint64At(val, 0), true, nil
}

func (attrs Attrs) GetUint64(typ uint16) (uint64, error) {
res, _, err := attrs.getUint64(typ, false)
return res, err
}

func (attrs Attrs) GetOptionalUint64(typ uint16) (uint64, bool, error) {
return attrs.getUint64(typ, true)
}

func (attrs Attrs) GetString(typ uint16) (string, error) {
val, err := attrs.Get(typ, false)
if err != nil {
Expand Down
4 changes: 4 additions & 0 deletions odp/unsafe.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ func int32At(data []byte, pos int) *int32 {
return (*int32)(unsafe.Pointer(&data[pos]))
}

func uint64At(data []byte, pos int) *uint64 {
return (*uint64)(unsafe.Pointer(&data[pos]))
}

func nlMsghdrAt(data []byte, pos int) *syscall.NlMsghdr {
return (*syscall.NlMsghdr)(unsafe.Pointer(&data[pos]))
}
Expand Down
34 changes: 31 additions & 3 deletions tool/odp/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,10 @@ var commands = subcommands{
"<datapath> <options>...", "Delete flow",
deleteFlow,
},
"clear": command{
"<datapath> <options>...", "Clear flow stats",
clearFlow,
},
"list": command{
"<datapath>", "List flows",
listFlows,
Expand Down Expand Up @@ -994,7 +998,31 @@ func deleteFlow(f Flags) bool {
return false
}

err = dp.DeleteFlow(flow)
err = dp.DeleteFlow(flow.FlowKeys)
if err != nil {
if odp.IsNoSuchFlowError(err) {
return printErr("No such flow")
} else {
return printErr("%s", err)
}
}

return true
}

func clearFlow(f Flags) bool {
dpif, err := odp.NewDpif()
if err != nil {
return printErr("%s", err)
}
defer dpif.Close()

dp, flow, ok := flagsToFlowSpec(f, dpif)
if !ok {
return false
}

err = dp.ClearFlow(flow.FlowKeys)
if err != nil {
if odp.IsNoSuchFlowError(err) {
return printErr("No such flow")
Expand Down Expand Up @@ -1041,8 +1069,8 @@ func listFlows(f Flags) bool {
}

if showStats {
fmt.Printf(": %d packets, %d bytes", flow.Packets,
flow.Bytes)
fmt.Printf(": %d packets, %d bytes, used %d",
flow.Packets, flow.Bytes, flow.Used)
}

os.Stdout.WriteString("\n")
Expand Down

0 comments on commit e56f0e7

Please sign in to comment.