Files
weave-scope/vendor/github.com/weaveworks/go-odp/odp/flow.go
2015-12-04 09:57:44 +00:00

1350 lines
28 KiB
Go

package odp
import (
"bytes"
"encoding/hex"
"fmt"
"net"
"syscall"
)
func AllBytes(data []byte, x byte) bool {
for _, y := range data {
if x != y {
return false
}
}
return true
}
type FlowKey interface {
typeId() uint16
putKeyNlAttr(*NlMsgBuilder)
putMaskNlAttr(*NlMsgBuilder) error
Ignored() bool
Equals(FlowKey) bool
}
type FlowKeys map[uint16]FlowKey
func (a FlowKeys) Equals(b FlowKeys) bool {
for id, ak := range a {
bk, ok := b[id]
if ok {
if !ak.Equals(bk) {
return false
}
} else {
if !ak.Ignored() {
return false
}
}
}
for id, bk := range b {
_, ok := a[id]
if !ok && !bk.Ignored() {
return false
}
}
return true
}
func (fks FlowKeys) toNlAttrs(msg *NlMsgBuilder) error {
// 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)
}
})
var err error
msg.PutNestedAttrs(OVS_FLOW_ATTR_MASK, func() {
for _, k := range fks {
if !k.Ignored() {
if e := k.putMaskNlAttr(msg); e != nil {
err = e
}
}
}
if defaultEthernetFlowKey != nil {
defaultEthernetFlowKey.putMaskNlAttr(msg)
}
})
return err
}
// A FlowKeyParser describes how to parse a flow key of a particular
// type from a netlnk message
type FlowKeyParser struct {
// Flow key parsing function
//
// key may be nil if the relevant attribute wasn't provided.
// This generally means that the mask will indicate that the
// flow key is Ignored.
parse func(typ uint16, key []byte, mask []byte, exact bool) (FlowKey, error)
// Special mask values indicating that the flow key is an
// exact match or Ignored. The parse function also receives
// an "exact" flag, to handle cases where the representation
// of the mask of awkward.
exactMask []byte
ignoreMask []byte
}
// Maps an NL attribute type to the corresponding FlowKeyParser
type FlowKeyParsers map[uint16]FlowKeyParser
func ParseFlowKeys(keys Attrs, masks Attrs) (res FlowKeys, err error) {
res = make(FlowKeys)
for typ, key := range keys {
parser, ok := flowKeyParsers[typ]
if !ok {
parser = FlowKeyParser{parse: parseUnknownFlowKey}
}
var mask []byte
exact := false
if masks == nil {
// "OVS_FLOW_ATTR_MASK: ... If not present,
// all flow key bits are exact match bits."
mask = parser.exactMask
exact = true
} else {
// "Omitting attribute is treated as
// wildcarding all corresponding fields"
mask, ok = masks[typ]
if !ok {
mask = parser.ignoreMask
}
}
res[typ], err = parser.parse(typ, key, mask, exact)
if err != nil {
return nil, err
}
}
if masks != nil {
for typ, mask := range masks {
_, ok := keys[typ]
if ok {
continue
}
// flow key mask without a corresponding flow
// key value
parser, ok := flowKeyParsers[typ]
if !ok {
parser = FlowKeyParser{parse: parseUnknownFlowKey}
}
res[typ], err = parser.parse(typ, nil, mask, false)
if err != nil {
return nil, err
}
}
}
return res, nil
}
// A flow key of a type we don't know about
type UnknownFlowKey struct {
typ uint16
key []byte
mask []byte // nil means ignored
exact bool
}
func parseUnknownFlowKey(typ uint16, key []byte, mask []byte, exact bool) (FlowKey, error) {
return UnknownFlowKey{typ: typ, key: key, mask: mask, exact: exact}, nil
}
func (key UnknownFlowKey) String() string {
var mask string
switch {
case key.exact:
mask = "exact"
case key.mask == nil:
mask = "ignored"
default:
mask = hex.EncodeToString(key.mask)
}
return fmt.Sprintf("UnknownFlowKey{type: %d, key: %s, mask: %s}",
key.typ, hex.EncodeToString(key.key), mask)
}
func (key UnknownFlowKey) typeId() uint16 {
return key.typ
}
func (key UnknownFlowKey) putKeyNlAttr(msg *NlMsgBuilder) {
msg.PutSliceAttr(key.typ, key.key)
}
func (key UnknownFlowKey) putMaskNlAttr(msg *NlMsgBuilder) error {
if key.exact {
return fmt.Errorf("cannot serialize exact mask for unknown flow key of type %d", key.typ)
}
if key.mask != nil {
msg.PutSliceAttr(key.typ, key.mask)
}
return nil
}
func (key UnknownFlowKey) Ignored() bool {
return key.mask == nil && !key.exact
}
func (a UnknownFlowKey) Equals(gb FlowKey) bool {
b, ok := gb.(UnknownFlowKey)
if !ok {
return false
}
if a.typ != b.typ || !bytes.Equal(a.key, b.key) {
return false
}
switch {
case a.exact:
return b.exact
case a.mask == nil:
return b.mask == nil
default:
return bytes.Equal(a.mask, b.mask)
}
}
// Most flow keys can be handled as opaque bytes.
type BlobFlowKey struct {
typ uint16
// This holds the key and the mask concatenated, so it is
// twice their length
keyMask []byte
}
func NewBlobFlowKey(typ uint16, size int) BlobFlowKey {
km := MakeAlignedByteSlice(size * 2)
mask := km[size:]
for i := range mask {
mask[i] = 0xff
}
return BlobFlowKey{typ: typ, keyMask: km}
}
func (key BlobFlowKey) String() string {
return fmt.Sprintf("BlobFlowKey{type: %d, key: %s, mask: %s}", key.typ,
hex.EncodeToString(key.key()), hex.EncodeToString(key.mask()))
}
func (key BlobFlowKey) typeId() uint16 {
return key.typ
}
func (key BlobFlowKey) key() []byte {
return key.keyMask[:len(key.keyMask)/2]
}
func (key BlobFlowKey) mask() []byte {
return key.keyMask[len(key.keyMask)/2:]
}
func (key BlobFlowKey) putKeyNlAttr(msg *NlMsgBuilder) {
msg.PutSliceAttr(key.typ, key.key())
}
func (key BlobFlowKey) putMaskNlAttr(msg *NlMsgBuilder) error {
msg.PutSliceAttr(key.typ, key.mask())
return nil
}
func (key BlobFlowKey) Ignored() bool {
return AllBytes(key.mask(), 0)
}
// Go's anonymous struct fields are not quite a replacement for
// inheritance. We want to have an Equals method for BlobFlowKeys,
// that works even when BlobFlowKeys are embedded as anonymous struct
// fields. But we can't use a straightforward type assertion to tell
// if another FlowKey is also a BlobFlowKey, because in the embedded
// case, it will say that the FlowKey is not an BlobFlowKey (the "has
// an anonymoys field of X" is not an "is a X" relation). To work
// around this, we use an interface, implemented by BlobFlowKey, that
// automatically gets promoted to all structs that embed BlobFlowKey.
type BlobFlowKeyish interface {
toBlobFlowKey() BlobFlowKey
}
func (key BlobFlowKey) toBlobFlowKey() BlobFlowKey { return key }
func (a BlobFlowKey) Equals(gb FlowKey) bool {
bx, ok := gb.(BlobFlowKeyish)
if !ok {
return false
}
b := bx.toBlobFlowKey()
if a.typ != b.typ {
return false
}
size := len(a.keyMask)
if len(b.keyMask) != size {
return false
}
size /= 2
amask := a.keyMask[size:]
bmask := b.keyMask[size:]
for i := range amask {
if amask[i] != bmask[i] || ((a.keyMask[i]^b.keyMask[i])&amask[i]) != 0 {
return false
}
}
return true
}
func parseBlobFlowKey(typ uint16, key []byte, mask []byte, size int) (BlobFlowKey, error) {
res := BlobFlowKey{typ: typ}
if len(mask) != size {
return res, fmt.Errorf("flow key mask type %d has wrong length (expected %d bytes, got %d)", typ, size, len(mask))
}
res.keyMask = MakeAlignedByteSlice(size * 2)
copy(res.keyMask[size:], mask)
if key != nil {
if len(key) != size {
return res, fmt.Errorf("flow key type %d has wrong length (expected %d bytes, got %d)", typ, size, len(key))
}
copy(res.keyMask, key)
} else {
// The kernel produces masks without a corresponding
// key, but in such cases the mask should indicate
// that the key value is ignored.
if !AllBytes(mask, 0) {
return res, fmt.Errorf("flow key type %d has non-zero mask without a value (mask %v)", typ, mask)
}
}
return res, nil
}
func blobFlowKeyParser(size int, wrap func(BlobFlowKey) FlowKey) FlowKeyParser {
exact := make([]byte, size)
for i := range exact {
exact[i] = 0xff
}
return FlowKeyParser{
parse: func(typ uint16, key []byte, mask []byte, exact bool) (FlowKey, error) {
bfk, err := parseBlobFlowKey(typ, key, mask, size)
if err != nil {
return nil, err
}
if wrap == nil {
return bfk, nil
} else {
return wrap(bfk), nil
}
},
ignoreMask: make([]byte, size),
exactMask: exact,
}
}
// OVS_KEY_ATTR_IN_PORT: Incoming port number
//
// This flow key is problematic. First, the kernel always does an
// exact match for IN_PORT, i.e. it takes the mask to be 0xffffffff if
// the key is set at all. Second, when reporting the mask, the kernel
// always sets the upper 16 bits, probably because port numbers are 16
// bits in the kernel, but 32 bits in the ABI to userspace. It does
// this even if the IN_PORT flow key was not set. As a result, we
// take any mask other than 0xffffffff to mean ignored.
type InPortFlowKey struct {
BlobFlowKey
}
func parseInPortFlowKey(typ uint16, key []byte, mask []byte, exact bool) (FlowKey, error) {
if !AllBytes(mask, 0xff) {
for i := range mask {
mask[i] = 0
}
}
fk, err := parseBlobFlowKey(typ, key, mask, 4)
if err != nil {
return nil, err
}
return InPortFlowKey{fk}, nil
}
func NewInPortFlowKey(vport VportID) FlowKey {
fk := InPortFlowKey{NewBlobFlowKey(OVS_KEY_ATTR_IN_PORT, 4)}
*uint32At(fk.key(), 0) = uint32(vport)
return fk
}
func (key InPortFlowKey) String() string {
return fmt.Sprintf("InPortFlowKey{vport: %d}", key.VportID())
}
func (k InPortFlowKey) VportID() VportID {
return VportID(*uint32At(k.key(), 0))
}
// OVS_KEY_ATTR_ETHERNET: Ethernet header flow key
type EthernetFlowKey struct {
BlobFlowKey
}
func (key EthernetFlowKey) Ignored() bool {
// An ethernet flow key is mandatory, so don't omit it just
// because the mask is all zeros
return false
}
func NewEthernetFlowKey() EthernetFlowKey {
return EthernetFlowKey{NewBlobFlowKey(OVS_KEY_ATTR_ETHERNET,
SizeofOvsKeyEthernet)}
}
func (fk *EthernetFlowKey) key() *OvsKeyEthernet {
return ovsKeyEthernetAt(fk.BlobFlowKey.key(), 0)
}
func (fk *EthernetFlowKey) mask() *OvsKeyEthernet {
return ovsKeyEthernetAt(fk.BlobFlowKey.mask(), 0)
}
func (fk EthernetFlowKey) Key() OvsKeyEthernet {
return *fk.key()
}
func (fk EthernetFlowKey) Mask() OvsKeyEthernet {
return *fk.mask()
}
func (fk *EthernetFlowKey) SetMaskedEthSrc(addr [ETH_ALEN]byte,
mask [ETH_ALEN]byte) {
fk.key().EthSrc = addr
fk.mask().EthSrc = mask
}
func (fk *EthernetFlowKey) SetEthSrc(addr [ETH_ALEN]byte) {
fk.SetMaskedEthSrc(addr, [...]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff})
}
func (fk *EthernetFlowKey) SetMaskedEthDst(addr [ETH_ALEN]byte,
mask [ETH_ALEN]byte) {
fk.key().EthDst = addr
fk.mask().EthDst = mask
}
func (fk *EthernetFlowKey) SetEthDst(addr [ETH_ALEN]byte) {
fk.SetMaskedEthDst(addr, [...]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff})
}
func (fk EthernetFlowKey) String() string {
var buf bytes.Buffer
var sep string
fmt.Fprint(&buf, "EthernetFlowKey{")
if fk.typ != OVS_KEY_ATTR_ETHERNET {
fmt.Fprintf(&buf, "type: %d", fk.typ)
sep = ", "
}
k := fk.Key()
m := fk.Mask()
ha := func(s []byte) string { return net.HardwareAddr(s).String() }
printMaskedBytes(&buf, &sep, "src", k.EthSrc[:], m.EthSrc[:], ha)
printMaskedBytes(&buf, &sep, "dst", k.EthDst[:], m.EthDst[:], ha)
fmt.Fprint(&buf, "}")
return buf.String()
}
func printMaskedBytes(buf *bytes.Buffer, sep *string, n string, k, m []byte,
s func([]byte) string) {
if !AllBytes(m, 0) {
fmt.Fprintf(buf, "%s%s: %s", *sep, n, s(k))
if !AllBytes(m, 0xff) {
fmt.Fprintf(buf, "&%s", s(m))
}
*sep = ", "
}
}
var ethernetFlowKeyParser = blobFlowKeyParser(SizeofOvsKeyEthernet,
func(fk BlobFlowKey) FlowKey { return EthernetFlowKey{fk} })
// OVS_KEY_ATTR_TUNNEL: Tunnel flow key. This is more elaborate than
// other flow keys because it consists of a set of attributes.
type TunnelAttrs struct {
TunnelId [8]byte
Ipv4Src [4]byte
Ipv4Dst [4]byte
Tos uint8
Ttl uint8
Df bool
Csum bool
TpSrc uint16
TpDst uint16
}
type TunnelAttrsPresence struct {
TunnelId bool
Ipv4Src bool
Ipv4Dst bool
Tos bool
Ttl bool
Df bool
Csum bool
TpSrc bool
TpDst bool
}
// Extract presence information from a TunnelAttrs mask
func (ta TunnelAttrs) present() TunnelAttrsPresence {
// The kernel requires Ipv4Dst and Ttl to be present, so we
// always mark those as present, even if we end up wildcarding
// them.
return TunnelAttrsPresence{
TunnelId: !AllBytes(ta.TunnelId[:], 0),
Ipv4Src: !AllBytes(ta.Ipv4Src[:], 0),
Ipv4Dst: true,
Tos: ta.Tos != 0,
Ttl: true,
Df: ta.Df,
Csum: ta.Csum,
TpSrc: ta.TpSrc != 0,
TpDst: ta.TpDst != 0,
}
}
// Convert a TunnelAttrsPresence to a mask
func (tap TunnelAttrsPresence) mask() (res TunnelAttrs) {
if tap.TunnelId {
res.TunnelId = [8]byte{
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
}
}
if tap.Ipv4Src {
res.Ipv4Src = [4]byte{0xff, 0xff, 0xff, 0xff}
}
if tap.Ipv4Dst {
res.Ipv4Dst = [4]byte{0xff, 0xff, 0xff, 0xff}
}
if tap.Tos {
res.Tos = 0xff
}
if tap.Ttl {
res.Ttl = 0xff
}
res.Df = tap.Df
res.Csum = tap.Csum
if tap.TpSrc {
res.TpSrc = 0xffff
}
if tap.TpDst {
res.TpDst = 0xffff
}
return
}
func (ta TunnelAttrs) toNlAttrs(msg *NlMsgBuilder, present TunnelAttrsPresence) {
if present.TunnelId {
msg.PutSliceAttr(OVS_TUNNEL_KEY_ATTR_ID, ta.TunnelId[:])
}
if present.Ipv4Src {
msg.PutSliceAttr(OVS_TUNNEL_KEY_ATTR_IPV4_SRC, ta.Ipv4Src[:])
}
if present.Ipv4Dst {
msg.PutSliceAttr(OVS_TUNNEL_KEY_ATTR_IPV4_DST, ta.Ipv4Dst[:])
}
if present.Tos {
msg.PutUint8Attr(OVS_TUNNEL_KEY_ATTR_TOS, ta.Tos)
}
if present.Ttl {
msg.PutUint8Attr(OVS_TUNNEL_KEY_ATTR_TTL, ta.Ttl)
}
if present.Df && ta.Df {
msg.PutEmptyAttr(OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT)
}
if present.Csum && ta.Csum {
msg.PutEmptyAttr(OVS_TUNNEL_KEY_ATTR_CSUM)
}
if present.TpSrc {
msg.PutUint16Attr(OVS_TUNNEL_KEY_ATTR_TP_SRC,
uint16ToBE(ta.TpSrc))
}
if present.TpDst {
msg.PutUint16Attr(OVS_TUNNEL_KEY_ATTR_TP_DST,
uint16ToBE(ta.TpDst))
}
}
func parseTunnelAttrs(data []byte) (ta TunnelAttrs, present TunnelAttrsPresence, err error) {
attrs, err := ParseNestedAttrs(data)
if err != nil {
return
}
present.TunnelId, err = attrs.GetOptionalBytes(OVS_TUNNEL_KEY_ATTR_ID, ta.TunnelId[:])
if err != nil {
return
}
present.Ipv4Src, err = attrs.GetOptionalBytes(OVS_TUNNEL_KEY_ATTR_IPV4_SRC, ta.Ipv4Src[:])
if err != nil {
return
}
present.Ipv4Dst, err = attrs.GetOptionalBytes(OVS_TUNNEL_KEY_ATTR_IPV4_DST, ta.Ipv4Dst[:])
ta.Tos, present.Tos, err = attrs.GetOptionalUint8(OVS_TUNNEL_KEY_ATTR_TOS)
if err != nil {
return
}
ta.Ttl, present.Ttl, err = attrs.GetOptionalUint8(OVS_TUNNEL_KEY_ATTR_TTL)
if err != nil {
return
}
ta.Df, err = attrs.GetEmpty(OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT)
present.Df = ta.Df
if err != nil {
return
}
ta.Csum, err = attrs.GetEmpty(OVS_TUNNEL_KEY_ATTR_CSUM)
present.Csum = ta.Csum
if err != nil {
return
}
ta.TpSrc, present.TpSrc, err = attrs.GetOptionalUint16(OVS_TUNNEL_KEY_ATTR_TP_SRC)
if err != nil {
return
}
ta.TpSrc = uint16FromBE(ta.TpSrc)
ta.TpDst, present.TpDst, err = attrs.GetOptionalUint16(OVS_TUNNEL_KEY_ATTR_TP_DST)
if err != nil {
return
}
ta.TpDst = uint16FromBE(ta.TpDst)
return
}
type TunnelFlowKey struct {
key TunnelAttrs
mask TunnelAttrs
}
func (fk TunnelFlowKey) String() string {
var buf bytes.Buffer
var sep string
fmt.Fprint(&buf, "TunnelFlowKey{")
printMaskedBytes(&buf, &sep, "id", fk.key.TunnelId[:],
fk.mask.TunnelId[:], hex.EncodeToString)
printMaskedBytes(&buf, &sep, "ipv4src", fk.key.Ipv4Src[:],
fk.mask.Ipv4Src[:], ipv4ToString)
printMaskedBytes(&buf, &sep, "ipv4dst", fk.key.Ipv4Dst[:],
fk.mask.Ipv4Dst[:], ipv4ToString)
printByte := func(n string, k, m byte) {
if m != 0 {
fmt.Fprintf(&buf, "%s%s: %d", sep, n, k)
if m != 0xff {
fmt.Fprintf(&buf, "&%x", m)
}
sep = ", "
}
}
printByte("tos", fk.key.Tos, fk.mask.Tos)
printByte("ttl", fk.key.Ttl, fk.mask.Ttl)
if fk.mask.Df {
fmt.Fprintf(&buf, "%sdf: %t", sep, fk.key.Df)
sep = ", "
}
if fk.mask.Csum {
fmt.Fprintf(&buf, "%ssum: %t", sep, fk.key.Csum)
sep = ", "
}
printUint16 := func(n string, k, m uint16) {
if m != 0 {
fmt.Fprintf(&buf, "%s%s: %d", sep, n, k)
if m != 0xffff {
fmt.Fprintf(&buf, "&%x", m)
}
sep = ", "
}
}
printUint16("tpsrc", fk.key.TpSrc, fk.mask.TpSrc)
printUint16("tpdst", fk.key.TpDst, fk.mask.TpDst)
fmt.Fprint(&buf, "}")
return buf.String()
}
func ipv4ToString(ip []byte) string {
return net.IP(ip).To4().String()
}
func (fk TunnelFlowKey) Key() TunnelAttrs {
return fk.key
}
func (fk TunnelFlowKey) Mask() TunnelAttrs {
return fk.mask
}
func (TunnelFlowKey) typeId() uint16 {
return OVS_KEY_ATTR_TUNNEL
}
func (fk *TunnelFlowKey) SetTunnelId(id [8]byte) {
fk.key.TunnelId = id
fk.mask.TunnelId = [...]byte{
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
}
}
func (fk *TunnelFlowKey) SetIpv4Src(addr [4]byte) {
fk.key.Ipv4Src = addr
fk.mask.Ipv4Src = [...]byte{0xff, 0xff, 0xff, 0xff}
}
func (fk *TunnelFlowKey) SetIpv4Dst(addr [4]byte) {
fk.key.Ipv4Dst = addr
fk.mask.Ipv4Dst = [...]byte{0xff, 0xff, 0xff, 0xff}
}
func (fk *TunnelFlowKey) SetTos(tos uint8) {
fk.key.Tos = tos
fk.mask.Tos = 0xff
}
func (fk *TunnelFlowKey) SetTtl(ttl uint8) {
fk.key.Ttl = ttl
fk.mask.Ttl = 0xff
}
func (fk *TunnelFlowKey) SetDf(df bool) {
fk.key.Df = df
fk.mask.Df = true
}
func (fk *TunnelFlowKey) SetCsum(csum bool) {
fk.key.Csum = csum
fk.mask.Csum = true
}
func (fk *TunnelFlowKey) SetTpSrc(port uint16) {
fk.key.TpSrc = port
fk.mask.TpSrc = 0xffff
}
func (fk *TunnelFlowKey) SetTpDst(port uint16) {
fk.key.TpDst = port
fk.mask.TpDst = 0xffff
}
func (key TunnelFlowKey) putKeyNlAttr(msg *NlMsgBuilder) {
msg.PutNestedAttrs(OVS_KEY_ATTR_TUNNEL, func() {
key.key.toNlAttrs(msg, key.mask.present())
})
}
func (key TunnelFlowKey) putMaskNlAttr(msg *NlMsgBuilder) error {
msg.PutNestedAttrs(OVS_KEY_ATTR_TUNNEL, func() {
key.mask.toNlAttrs(msg, key.mask.present())
})
return nil
}
func (a TunnelFlowKey) Equals(gb FlowKey) bool {
b, ok := gb.(TunnelFlowKey)
if !ok {
return false
}
return a.key == b.key && a.mask == b.mask
}
func (key TunnelFlowKey) Ignored() bool {
m := key.mask
return AllBytes(m.TunnelId[:], 0) &&
AllBytes(m.Ipv4Src[:], 0) &&
AllBytes(m.Ipv4Dst[:], 0) &&
m.Tos == 0 &&
m.Ttl == 0 &&
!m.Csum && !m.Csum &&
m.TpSrc == 0 && m.TpDst == 0
}
func parseTunnelFlowKey(typ uint16, key []byte, mask []byte, exact bool) (FlowKey, error) {
var k, m TunnelAttrs
var kp TunnelAttrsPresence
var err error
if key != nil {
k, kp, err = parseTunnelAttrs(key)
if err != nil {
return nil, err
}
}
if mask != nil {
// We don't care about mask presence information,
// because a missing mask attribute means the field is
// wildcarded
m, _, err = parseTunnelAttrs(mask)
if err != nil {
return nil, err
}
} else {
// mask being nil means that no mask attributes were
// provided, which means the mask is implicit in the
// key attributes provided
m = kp.mask()
}
return TunnelFlowKey{key: k, mask: m}, err
}
var flowKeyParsers = FlowKeyParsers{
// Packet QoS priority flow key
OVS_KEY_ATTR_PRIORITY: blobFlowKeyParser(4, nil),
OVS_KEY_ATTR_IN_PORT: FlowKeyParser{
parse: parseInPortFlowKey,
exactMask: []byte{0xff, 0xff, 0xff, 0xff},
ignoreMask: []byte{0, 0, 0, 0},
},
OVS_KEY_ATTR_ETHERNET: ethernetFlowKeyParser,
OVS_KEY_ATTR_ETHERTYPE: blobFlowKeyParser(2, nil),
OVS_KEY_ATTR_IPV4: blobFlowKeyParser(12, nil),
OVS_KEY_ATTR_IPV6: blobFlowKeyParser(40, nil),
OVS_KEY_ATTR_TCP: blobFlowKeyParser(4, nil),
OVS_KEY_ATTR_UDP: blobFlowKeyParser(4, nil),
OVS_KEY_ATTR_ICMP: blobFlowKeyParser(2, nil),
OVS_KEY_ATTR_ICMPV6: blobFlowKeyParser(2, nil),
OVS_KEY_ATTR_ARP: blobFlowKeyParser(24, nil),
OVS_KEY_ATTR_ND: blobFlowKeyParser(28, nil),
OVS_KEY_ATTR_SKB_MARK: blobFlowKeyParser(4, nil),
OVS_KEY_ATTR_DP_HASH: blobFlowKeyParser(4, nil),
OVS_KEY_ATTR_TCP_FLAGS: blobFlowKeyParser(2, nil),
OVS_KEY_ATTR_RECIRC_ID: blobFlowKeyParser(4, nil),
OVS_KEY_ATTR_TUNNEL: FlowKeyParser{
parse: parseTunnelFlowKey,
exactMask: nil,
ignoreMask: []byte{},
},
}
func MakeFlowKeys() FlowKeys {
return make(FlowKeys)
}
func (keys FlowKeys) Add(k FlowKey) {
// TODO check for collisions
keys[k.typeId()] = k
}
// Actions
type Action interface {
typeId() uint16
toNlAttr(*NlMsgBuilder)
Equals(Action) bool
}
type OutputAction VportID
func NewOutputAction(vport VportID) OutputAction {
return OutputAction(vport)
}
func (oa OutputAction) String() string {
return fmt.Sprintf("OutputAction{vport: %d}", oa)
}
func (oa OutputAction) VportID() VportID {
return VportID(oa)
}
func (OutputAction) typeId() uint16 {
return OVS_ACTION_ATTR_OUTPUT
}
func (oa OutputAction) toNlAttr(msg *NlMsgBuilder) {
msg.PutUint32Attr(OVS_ACTION_ATTR_OUTPUT, uint32(oa))
}
func (a OutputAction) Equals(bx Action) bool {
b, ok := bx.(OutputAction)
if !ok {
return false
}
return a == b
}
func parseOutputAction(typ uint16, data []byte) (Action, error) {
if len(data) < 4 {
return nil, fmt.Errorf("flow action type %d has wrong length (expects 4 bytes, got %d)", typ, len(data))
}
return OutputAction(*uint32At(data, 0)), nil
}
type SetTunnelAction struct {
TunnelAttrs
Present TunnelAttrsPresence
}
func (ta SetTunnelAction) String() string {
var buf bytes.Buffer
var sep string
fmt.Fprint(&buf, "SetTunnelAction{")
if ta.Present.TunnelId {
fmt.Fprintf(&buf, "%sid: %s", sep,
hex.EncodeToString(ta.TunnelId[:]))
sep = ", "
}
if ta.Present.Ipv4Src {
fmt.Fprintf(&buf, "%sipv4src: %s", sep,
ipv4ToString(ta.Ipv4Src[:]))
sep = ", "
}
if ta.Present.Ipv4Dst {
fmt.Fprintf(&buf, "%sipv4dst: %s", sep,
ipv4ToString(ta.Ipv4Dst[:]))
sep = ", "
}
if ta.Present.Tos {
fmt.Fprintf(&buf, "%stos: %d", sep, ta.Tos)
sep = ", "
}
if ta.Present.Ttl {
fmt.Fprintf(&buf, "%sttl: %d", sep, ta.Ttl)
sep = ", "
}
if ta.Present.Df {
fmt.Fprintf(&buf, "%sdf: %t", sep, ta.Df)
sep = ", "
}
if ta.Present.Csum {
fmt.Fprintf(&buf, "%scsum: %t", sep, ta.Csum)
sep = ", "
}
if ta.Present.TpSrc {
fmt.Fprintf(&buf, "%stpsrc: %d", sep, ta.TpSrc)
sep = ", "
}
if ta.Present.TpDst {
fmt.Fprintf(&buf, "%stpdst: %d", sep, ta.TpDst)
sep = ", "
}
fmt.Fprint(&buf, "}")
return buf.String()
}
func (SetTunnelAction) typeId() uint16 {
return OVS_ACTION_ATTR_SET
}
func (ta SetTunnelAction) toNlAttr(msg *NlMsgBuilder) {
msg.PutNestedAttrs(OVS_ACTION_ATTR_SET, func() {
msg.PutNestedAttrs(OVS_KEY_ATTR_TUNNEL, func() {
ta.Present.Df = ta.Df
ta.Present.Csum = ta.Csum
ta.TunnelAttrs.toNlAttrs(msg, ta.Present)
})
})
}
func (a SetTunnelAction) Equals(bx Action) bool {
b, ok := bx.(SetTunnelAction)
if !ok {
return false
}
return a.TunnelAttrs == b.TunnelAttrs
}
func (a *SetTunnelAction) SetTunnelId(id [8]byte) {
a.TunnelId = id
a.Present.TunnelId = true
}
func (a *SetTunnelAction) SetIpv4Src(addr [4]byte) {
a.Ipv4Src = addr
a.Present.Ipv4Src = true
}
func (a *SetTunnelAction) SetIpv4Dst(addr [4]byte) {
a.Ipv4Dst = addr
a.Present.Ipv4Dst = true
}
func (a *SetTunnelAction) SetTos(tos uint8) {
a.Tos = tos
a.Present.Tos = true
}
func (a *SetTunnelAction) SetTtl(ttl uint8) {
a.Ttl = ttl
a.Present.Ttl = true
}
func (a *SetTunnelAction) SetDf(df bool) {
a.Df = df
a.Present.Df = true
}
func (a *SetTunnelAction) SetCsum(csum bool) {
a.Csum = csum
a.Present.Csum = true
}
func (a *SetTunnelAction) SetTpSrc(port uint16) {
a.TpSrc = port
a.Present.TpSrc = true
}
func (a *SetTunnelAction) SetTpDst(port uint16) {
a.TpDst = port
a.Present.TpDst = true
}
func parseSetAction(typ uint16, data []byte) (Action, error) {
attrs, err := ParseNestedAttrs(data)
if err != nil {
return nil, err
}
var res Action
first := true
for typ, data := range attrs {
if !first {
return nil, fmt.Errorf("multiple attributes within OVS_ACTION_ATTR_SET")
}
switch typ {
case OVS_KEY_ATTR_TUNNEL:
ta, present, err := parseTunnelAttrs(data)
if err != nil {
return nil, err
}
res = SetTunnelAction{TunnelAttrs: ta, Present: present}
break
default:
return nil, fmt.Errorf("unsupported OVS_ACTION_ATTR_SET attribute %d", typ)
}
first = false
}
return res, nil
}
var actionParsers = map[uint16](func(uint16, []byte) (Action, error)){
OVS_ACTION_ATTR_OUTPUT: parseOutputAction,
OVS_ACTION_ATTR_SET: parseSetAction,
}
// Complete flows
type FlowSpec struct {
FlowKeys
Actions []Action
}
func NewFlowSpec() FlowSpec {
return FlowSpec{FlowKeys: make(FlowKeys), Actions: nil}
}
func (f FlowSpec) String() string {
var keys []FlowKey
for _, k := range f.FlowKeys {
keys = append(keys, k)
}
return fmt.Sprintf("FlowSpec{keys: %v, actions: %v}", keys, f.Actions)
}
func (f *FlowSpec) AddKey(k FlowKey) {
f.FlowKeys.Add(k)
}
func (f *FlowSpec) AddAction(a Action) {
f.Actions = append(f.Actions, a)
}
func (f *FlowSpec) AddActions(as []Action) {
f.Actions = append(f.Actions, as...)
}
func (f FlowSpec) toNlAttrs(msg *NlMsgBuilder) error {
if err := f.FlowKeys.toNlAttrs(msg); err != nil {
return err
}
msg.PutNestedAttrs(OVS_FLOW_ATTR_ACTIONS, func() {
for _, a := range f.Actions {
a.toNlAttr(msg)
}
})
return nil
}
func (a FlowSpec) Equals(b FlowSpec) bool {
if !a.FlowKeys.Equals(b.FlowKeys) {
return false
}
if len(a.Actions) != len(b.Actions) {
return false
}
for i := range a.Actions {
if !a.Actions[i].Equals(b.Actions[i]) {
return false
}
}
return true
}
func (dp DatapathHandle) parseFlowMsg(msg *NlMsgParser) (Attrs, error) {
if err := dp.checkNlMsgHeaders(msg, FLOW, OVS_FLOW_CMD_NEW); err != nil {
return nil, err
}
return msg.TakeAttrs()
}
func parseFlowSpec(attrs Attrs) (f FlowSpec, err error) {
keys, err := attrs.GetNestedAttrs(OVS_FLOW_ATTR_KEY, false)
if err != nil {
return f, err
}
masks, err := attrs.GetNestedAttrs(OVS_FLOW_ATTR_MASK, true)
if err != nil {
return f, err
}
f.FlowKeys, err = ParseFlowKeys(keys, masks)
if err != nil {
return f, err
}
actattrs, err := attrs.GetOrderedAttrs(OVS_FLOW_ATTR_ACTIONS)
if err != nil {
return f, err
}
actions := make([]Action, 0)
for _, actattr := range actattrs {
parser, ok := actionParsers[actattr.typ]
if !ok {
return f, fmt.Errorf("unknown action type %d (value %v)", actattr.typ, actattr.val)
}
action, err := parser(actattr.typ, actattr.val)
if err != nil {
return f, err
}
actions = append(actions, action)
}
f.Actions = actions
return f, nil
}
func (dp DatapathHandle) CreateFlow(f FlowSpec) error {
dpif := dp.dpif
req := NewNlMsgBuilder(RequestFlags, dpif.families[FLOW].id)
req.PutGenlMsghdr(OVS_FLOW_CMD_NEW, OVS_FLOW_VERSION)
req.putOvsHeader(dp.ifindex)
if err := f.toNlAttrs(req); err != nil {
return err
}
_, err := dpif.sock.Request(req)
return err
}
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)
if err := fks.toNlAttrs(req); err != nil {
return err
}
_, err := dpif.sock.Request(req)
return err
}
func (dp DatapathHandle) ClearFlow(f FlowSpec) error {
dpif := dp.dpif
req := NewNlMsgBuilder(RequestFlags, dpif.families[FLOW].id)
req.PutGenlMsghdr(OVS_FLOW_CMD_SET, OVS_FLOW_VERSION)
req.putOvsHeader(dp.ifindex)
if err := f.toNlAttrs(req); err != nil {
return err
}
req.PutEmptyAttr(OVS_FLOW_ATTR_CLEAR)
_, err := dpif.sock.Request(req)
return err
}
func IsNoSuchFlowError(err error) bool {
return err == NetlinkError(syscall.ENOENT)
}
type FlowInfo struct {
FlowSpec
Packets uint64
Bytes uint64
Used uint64
}
func parseFlowInfo(attrs Attrs) (fi FlowInfo, err error) {
fi.FlowSpec, err = parseFlowSpec(attrs)
if err != nil {
return
}
statsBytes, err := attrs.GetFixedBytes(OVS_FLOW_ATTR_STATS,
SizeofOvsFlowStats, true)
if err != nil {
return
}
if statsBytes != nil {
stats := ovsFlowStatsAt(statsBytes, 0)
fi.Packets = stats.NPackets
fi.Bytes = stats.NBytes
}
used, usedPresent, err := attrs.GetOptionalUint64(OVS_FLOW_ATTR_USED)
if err != nil {
return
} else if usedPresent {
fi.Used = used
}
return
}
func (dp DatapathHandle) EnumerateFlows() ([]FlowInfo, error) {
dpif := dp.dpif
res := make([]FlowInfo, 0)
req := NewNlMsgBuilder(DumpFlags, dpif.families[FLOW].id)
req.PutGenlMsghdr(OVS_FLOW_CMD_GET, OVS_FLOW_VERSION)
req.putOvsHeader(dp.ifindex)
consumer := func(resp *NlMsgParser) error {
attrs, err := dp.parseFlowMsg(resp)
if err != nil {
return err
}
fi, err := parseFlowInfo(attrs)
if err != nil {
return err
}
res = append(res, fi)
return nil
}
err := dpif.sock.RequestMulti(req, consumer)
if err != nil {
return nil, err
}
return res, nil
}