func (self OxmKeyExp) Bytes(payload OxmPayload) []byte { hdr := oxm.Header(oxm.OFPXMC_EXPERIMENTER<<oxm.OXM_CLASS_SHIFT | uint32(self.Field)<<oxm.OXM_FIELD_SHIFT) var buf []byte setCommon := func(payloadLength int) { buf = make([]byte, 4+payloadLength) hdr.SetLength(payloadLength) binary.BigEndian.PutUint32(buf, uint32(hdr)) binary.BigEndian.PutUint32(buf[4:], self.Experimenter) binary.BigEndian.PutUint16(buf[8:], self.Type) } switch p := payload.(type) { case OxmValueMask: if len(p.Mask) > 0 { hdr.SetMask(true) } setCommon(6 + len(p.Value) + len(p.Mask)) copy(buf[10:], p.Value) copy(buf[10+len(p.Value):], p.Mask) case []byte: setCommon(6 + len(p)) copy(buf[10:], p) case nil: setCommon(6) } return buf }
func (self OxmKeyStratos) Bytes(payload ofp4sw.OxmPayload) []byte { hdr := oxm.Header(oxm.OFPXMC_EXPERIMENTER<<oxm.OXM_CLASS_SHIFT | uint32(self.Field)<<oxm.OXM_FIELD_SHIFT) makeCommon := func(payloadLength int) []byte { buf := make([]byte, 10+payloadLength) hdr.SetLength(6 + payloadLength) binary.BigEndian.PutUint32(buf, uint32(hdr)) binary.BigEndian.PutUint32(buf[4:], uint32(oxm.STRATOS_EXPERIMENTER_ID)) binary.BigEndian.PutUint16(buf[8:], self.Type) return buf } switch p := payload.(type) { case ofp4sw.OxmValueMask: if len(p.Mask) > 0 { hdr.SetMask(true) } buf := makeCommon(len(p.Value) + len(p.Mask)) copy(buf[10:], p.Value) copy(buf[10+len(p.Value):], p.Mask) return buf case OxmMultiValue: var ret []byte for _, v := range p.Values { buf := makeCommon(len(v)) copy(buf[10:], v) ret = append(ret, buf...) } return ret } return nil }
func (self matchHash) Key(target matchHash) uint32 { hasher := fnv.New32() for k, s := range self { var value, mask []byte if bKey, ok := k.(OxmKeyBasic); !ok || oxm.Header(bKey).Class() != ofp4.OFPXMC_OPENFLOW_BASIC { continue } else { length, _ := ofp4.OxmOfDefs(uint32(bKey)) value = make([]byte, length) mask = make([]byte, length) } if t, ok := target[k]; ok { a := s.(OxmValueMask) b := t.(OxmValueMask) for i, _ := range mask { mask[i] = 0xFF } if a.Mask != nil { for i, _ := range mask { mask[i] &= a.Mask[i] } } if b.Mask != nil { for i, _ := range mask { mask[i] &= b.Mask[i] } } for i, _ := range value { value[i] = b.Value[i] & mask[i] } } hasher.Write(value) } return hasher.Sum32() }
func (self match) Match(data Frame) bool { for oxmKey, oxmPayload := range self { var handler OxmHandler switch k := oxmKey.(type) { case OxmKeyBasic: switch oxm.Header(k).Class() { case ofp4.OFPXMC_OPENFLOW_BASIC: handler = oxmBasicHandler case ofp4.OFPXMC_NXM_0, OFPXMC_NXM_1: handler = oxmNxmHandler } default: handler = oxmHandlers[oxmKeys[oxmKey]] } if handler == nil { log.Printf("oxm handler not found for %v", oxmKey) return false } if result, err := handler.Match(data, oxmKey, oxmPayload); err != nil { log.Print(err) return false } else if !result { return false } } return true }
func (self match) UnmarshalBinary(msg []byte) error { exps := make(map[uint32]bool) for _, oxm := range ofp4.Oxm(msg).Iter() { hdr := oxm.Header() switch hdr.Class() { case ofp4.OFPXMC_OPENFLOW_BASIC: self[OxmKeyBasic(hdr.Type())] = OxmValueMask{ Value: oxm.Value(), Mask: oxm.Mask(), } case ofp4.OFPXMC_EXPERIMENTER: exps[ofp4.OxmExperimenterHeader(oxm).Experimenter()] = true default: return ofp4.MakeErrorMsg( ofp4.OFPET_BAD_MATCH, ofp4.OFPBMC_BAD_TYPE, ) } } for exp, _ := range exps { if handle, ok := oxmHandlers[exp]; ok { for k, v := range handle.Parse(msg) { oxmKeys[k] = exp self[k] = v } } else { return ofp4.MakeErrorMsg( ofp4.OFPET_BAD_MATCH, ofp4.OFPBRC_BAD_LEN, ) } } return nil }
func (self oxmNxm) OxmId(id uint32) uint32 { length, mask := nxmDefs(id) hdr := oxm.Header(id) hdr.SetMask(mask) if mask { hdr.SetLength(length * 2) } else { hdr.SetLength(length) } return uint32(hdr) }
// creates a common match union parameter. func (self matchHash) Merge(from matchHash) { var removal []OxmKey for k, s := range self { var a, b OxmValueMask var length int if bKey, ok := k.(OxmKeyBasic); !ok || oxm.Header(bKey).Class() != ofp4.OFPXMC_OPENFLOW_BASIC { continue } else if f, ok := from[k]; !ok { removal = append(removal, k) continue } else { a = s.(OxmValueMask) b = f.(OxmValueMask) length, _ = ofp4.OxmOfDefs(uint32(bKey)) } fullMask := true mask := make([]byte, length) for i, _ := range mask { mask[i] = 0xFF } if a.Mask != nil { for i, _ := range mask { mask[i] &= a.Mask[i] } } if b.Mask != nil { for i, _ := range mask { mask[i] &= b.Mask[i] } } for i, m := range mask { mask[i] &^= (a.Value[i] & m) ^ (b.Value[i] & m) if mask[i] != 0 { fullMask = false } } if fullMask { removal = append(removal, k) continue } payload := OxmValueMask{ Value: make([]byte, length), Mask: mask, } for i, m := range mask { payload.Value[i] = a.Value[i] & m } self[k] = payload } for _, rem := range removal { delete(self, rem) } }
func makeOxmBasic(oxmType uint32) []byte { length, mask := ofp4.OxmOfDefs(oxmType) if mask { length = length * 2 } hdr := oxm.Header(oxmType) hdr.SetMask(mask) hdr.SetLength(length) buf := make([]byte, 4+length) binary.BigEndian.PutUint32(buf, oxmType) return buf }
func (self OxmKeyBasic) Bytes(payload OxmPayload) []byte { vm := payload.(OxmValueMask) buf := make([]byte, 4+len(vm.Value)+len(vm.Mask)) hdr := oxm.Header(self) if len(vm.Mask) > 0 { hdr.SetMask(true) } hdr.SetLength(len(buf) - 4) binary.BigEndian.PutUint32(buf, uint32(hdr)) copy(buf[4:], vm.Value) copy(buf[4+len(vm.Value):], vm.Mask) return buf }
func (self oxmNxm) Parse(buf []byte) map[OxmKey]OxmPayload { ret := make(map[OxmKey]OxmPayload) for _, oxm := range ofp4.Oxm(buf).Iter() { hdr := oxm.Header() length := hdr.Length() if hdr.HasMask() { length = length / 2 } switch hdr.Class() { case ofp4.OFPXMC_NXM_0, ofp4.OFPXMC_NXM_1: ret[OxmKeyBasic(hdr.Type())] = OxmValueMask{ Value: oxm[4 : 4+length], Mask: oxm[4+length:], } } } return ret }
func (self OxmKeyExp) Bytes(payload OxmPayload) []byte { hdr := oxm.Header(oxm.OFPXMC_EXPERIMENTER<<oxm.OXM_CLASS_SHIFT | uint32(self.Field)<<oxm.OXM_FIELD_SHIFT) var value, mask []byte switch p := payload.(type) { case OxmValueMask: value = p.Value mask = p.Mask case []byte: value = p } if len(mask) > 0 { hdr.SetMask(true) } buf = make([]byte, 8+len(value)+len(mask)) hdr.SetLength(4 + len(value) + len(mask)) binary.BigEndian.PutUint32(buf, uint32(hdr)) binary.BigEndian.PutUint32(buf[4:], self.Experimenter) copy(buf[8:], value) copy(buf[8+len(value):], mask) return buf }
/* You should pass expanded match. */ func (self match) Conflict(target match) (bool, error) { uni := make(map[OxmKey]bool) for k, _ := range self { uni[k] = true } for k, _ := range target { uni[k] = true } for oxmKey, _ := range uni { if sPayload, ok := self[oxmKey]; !ok { continue } else if tPayload, ok := target[oxmKey]; !ok { continue } else { var handle OxmHandler switch k := oxmKey.(type) { case OxmKeyBasic: if oxm.Header(k).Class() == ofp4.OFPXMC_OPENFLOW_BASIC { handle = oxmBasicHandler } default: handle = oxmHandlers[oxmKeys[oxmKey]] } if handle == nil { return false, ofp4.MakeErrorMsg( ofp4.OFPET_BAD_MATCH, ofp4.OFPBMC_BAD_TYPE, ) } if result, err := handle.Conflict(oxmKey, sPayload, tPayload); err != nil { return false, err } else if result { return true, nil } } } return false, nil }
func (self match) Expand() (match, error) { var exps []uint32 ret := make(map[OxmKey]OxmPayload) for k, v := range self { oxm := ofp4.Oxm(k.Bytes(v)) if oxm.Header().Class() == ofp4.OFPXMC_EXPERIMENTER { exps = append(exps, ofp4.OxmExperimenterHeader(oxm).Experimenter()) } ret[k] = v } oxmBasicHandler.Expand(ret) for _, exp := range exps { if handle, ok := oxmHandlers[exp]; !ok { return nil, ofp4.MakeErrorMsg( ofp4.OFPET_BAD_MATCH, ofp4.OFPBMC_BAD_TYPE, ) } else if err := handle.Expand(ret); err != nil { return nil, err } } return ret, nil }
func OxmOfDefs(hdr uint32) (length int, mayMask bool) { switch oxm.Header(hdr).Type() { default: return 0, false case oxm.OXM_OF_IN_PORT: return 4, false case oxm.OXM_OF_IN_PHY_PORT: return 4, false case oxm.OXM_OF_METADATA: return 8, true case oxm.OXM_OF_ETH_DST: return 6, true case oxm.OXM_OF_ETH_SRC: return 6, true case oxm.OXM_OF_ETH_TYPE: return 2, false case oxm.OXM_OF_VLAN_VID: return 2, true case oxm.OXM_OF_VLAN_PCP: return 1, false case oxm.OXM_OF_IP_DSCP: return 1, false case oxm.OXM_OF_IP_ECN: return 1, false case oxm.OXM_OF_IP_PROTO: return 1, false case oxm.OXM_OF_IPV4_SRC: return 4, true case oxm.OXM_OF_IPV4_DST: return 4, true case oxm.OXM_OF_TCP_SRC: return 2, false case oxm.OXM_OF_TCP_DST: return 2, false case oxm.OXM_OF_UDP_SRC: return 2, false case oxm.OXM_OF_UDP_DST: return 2, false case oxm.OXM_OF_SCTP_SRC: return 2, false case oxm.OXM_OF_SCTP_DST: return 2, false case oxm.OXM_OF_ICMPV4_TYPE: return 1, false case oxm.OXM_OF_ICMPV4_CODE: return 1, false case oxm.OXM_OF_ARP_OP: return 2, false case oxm.OXM_OF_ARP_SPA: return 4, true case oxm.OXM_OF_ARP_TPA: return 4, true case oxm.OXM_OF_ARP_SHA: return 6, true case oxm.OXM_OF_ARP_THA: return 6, true case oxm.OXM_OF_IPV6_SRC: return 16, true case oxm.OXM_OF_IPV6_DST: return 16, true case oxm.OXM_OF_IPV6_FLABEL: return 4, true case oxm.OXM_OF_ICMPV6_TYPE: return 1, false case oxm.OXM_OF_ICMPV6_CODE: return 1, false case oxm.OXM_OF_IPV6_ND_TARGET: return 16, false case oxm.OXM_OF_IPV6_ND_SLL: return 6, false case oxm.OXM_OF_IPV6_ND_TLL: return 6, false case oxm.OXM_OF_MPLS_LABEL: return 4, true case oxm.OXM_OF_MPLS_TC: return 1, false case oxm.OXM_OF_MPLS_BOS: return 1, false case oxm.OXM_OF_PBB_ISID: return 3, true case oxm.OXM_OF_TUNNEL_ID: return 8, true case oxm.OXM_OF_IPV6_EXTHDR: return 2, true } }
func (self Oxm) Header() oxm.Header { return oxm.Header(binary.BigEndian.Uint32(self)) }
func (self *Frame) getValue(oxmType uint32) ([]byte, error) { switch oxm.Header(oxmType).Type() { default: return nil, fmt.Errorf("unknown oxm field %x", oxmType) case oxm.OXM_OF_IN_PORT: return toMatchBytes(self.inPort) case oxm.OXM_OF_IN_PHY_PORT: return toMatchBytes(self.inPhyPort) case oxm.OXM_OF_METADATA: return toMatchBytes(self.metadata) case oxm.OXM_OF_ETH_DST: for _, layer := range self.Layers() { if t, ok := layer.(*layers.Ethernet); ok { return toMatchBytes(t.DstMAC) } } case oxm.OXM_OF_ETH_SRC: for _, layer := range self.Layers() { if t, ok := layer.(*layers.Ethernet); ok { return toMatchBytes(t.SrcMAC) } } case oxm.OXM_OF_ETH_TYPE: do_break := false var ret []byte for _, layer := range self.Layers() { switch t := layer.(type) { case *layers.Ethernet: if buf, err := toMatchBytes(t.EthernetType); err != nil { return nil, err } else { ret = buf } case *layers.Dot1Q: if buf, err := toMatchBytes(t.Type); err != nil { return nil, err } else { ret = buf } default: do_break = true } if do_break { break } } if ret != nil { return ret, nil } case oxm.OXM_OF_VLAN_VID: for _, layer := range self.Layers() { if t, ok := layer.(*layers.Dot1Q); ok { return toMatchBytes(t.VLANIdentifier | 0x1000) } } return toMatchBytes(uint16(0x0000)) case oxm.OXM_OF_VLAN_PCP: for _, layer := range self.Layers() { if t, ok := layer.(*layers.Dot1Q); ok { return toMatchBytes(t.Priority) } } case oxm.OXM_OF_IP_DSCP: for _, layer := range self.Layers() { if t, ok := layer.(*layers.IPv4); ok { return toMatchBytes(t.TOS >> 2) } if t, ok := layer.(*layers.IPv6); ok { return toMatchBytes(t.TrafficClass >> 2) } } case oxm.OXM_OF_IP_ECN: for _, layer := range self.Layers() { if t, ok := layer.(*layers.IPv4); ok { return toMatchBytes(t.TOS & 0x03) } if t, ok := layer.(*layers.IPv6); ok { return toMatchBytes(t.TrafficClass & 0x03) } } case oxm.OXM_OF_IP_PROTO: for _, layer := range self.Layers() { if t, ok := layer.(*layers.IPv4); ok { return toMatchBytes(t.Protocol) } if t, ok := layer.(*layers.IPv6); ok { return toMatchBytes(t.NextHeader) } } case oxm.OXM_OF_IPV4_SRC: for _, layer := range self.Layers() { if t, ok := layer.(*layers.IPv4); ok { return toMatchBytes(t.SrcIP) } } case oxm.OXM_OF_IPV4_DST: for _, layer := range self.Layers() { if t, ok := layer.(*layers.IPv4); ok { return toMatchBytes(t.DstIP) } } case oxm.OXM_OF_TCP_SRC: for _, layer := range self.Layers() { if t, ok := layer.(*layers.TCP); ok { return toMatchBytes(t.SrcPort) } } case oxm.OXM_OF_TCP_DST: for _, layer := range self.Layers() { if t, ok := layer.(*layers.TCP); ok { return toMatchBytes(t.DstPort) } } case oxm.OXM_OF_UDP_SRC: for _, layer := range self.Layers() { if t, ok := layer.(*layers.UDP); ok { return toMatchBytes(t.SrcPort) } } case oxm.OXM_OF_UDP_DST: for _, layer := range self.Layers() { if t, ok := layer.(*layers.UDP); ok { return toMatchBytes(t.DstPort) } } case oxm.OXM_OF_SCTP_SRC: for _, layer := range self.Layers() { if t, ok := layer.(*layers.SCTP); ok { return toMatchBytes(t.SrcPort) } } case oxm.OXM_OF_SCTP_DST: for _, layer := range self.Layers() { if t, ok := layer.(*layers.SCTP); ok { return toMatchBytes(t.DstPort) } } case oxm.OXM_OF_ICMPV4_TYPE: for _, layer := range self.Layers() { if t, ok := layer.(*layers.ICMPv4); ok { if buf, err := toMatchBytes(t.TypeCode); err != nil { return nil, err } else { return buf[:1], nil } } } case oxm.OXM_OF_ICMPV4_CODE: for _, layer := range self.Layers() { if t, ok := layer.(*layers.ICMPv4); ok { if buf, err := toMatchBytes(t.TypeCode); err != nil { return nil, err } else { return buf[1:], nil } } } case oxm.OXM_OF_ARP_OP: for _, layer := range self.Layers() { if t, ok := layer.(*layers.ARP); ok { return toMatchBytes(t.Operation) } } case oxm.OXM_OF_ARP_SPA: for _, layer := range self.Layers() { if t, ok := layer.(*layers.ARP); ok { return toMatchBytes(t.SourceProtAddress) } } case oxm.OXM_OF_ARP_TPA: for _, layer := range self.Layers() { if t, ok := layer.(*layers.ARP); ok { return toMatchBytes(t.DstProtAddress) } } case oxm.OXM_OF_ARP_SHA: for _, layer := range self.Layers() { if t, ok := layer.(*layers.ARP); ok { return toMatchBytes(t.SourceHwAddress) } } case oxm.OXM_OF_ARP_THA: for _, layer := range self.Layers() { if t, ok := layer.(*layers.ARP); ok { return toMatchBytes(t.DstHwAddress) } } case oxm.OXM_OF_IPV6_SRC: for _, layer := range self.Layers() { if t, ok := layer.(*layers.IPv6); ok { return toMatchBytes(t.SrcIP) } } case oxm.OXM_OF_IPV6_DST: for _, layer := range self.Layers() { if t, ok := layer.(*layers.IPv6); ok { return toMatchBytes(t.DstIP) } } case oxm.OXM_OF_IPV6_FLABEL: for _, layer := range self.Layers() { if t, ok := layer.(*layers.IPv6); ok { return toMatchBytes(t.FlowLabel) } } case oxm.OXM_OF_ICMPV6_TYPE: for _, layer := range self.Layers() { if t, ok := layer.(*layers.ICMPv6); ok { if buf, err := toMatchBytes(t.TypeCode); err != nil { return nil, err } else { return buf[:1], nil } } } case oxm.OXM_OF_ICMPV6_CODE: for _, layer := range self.Layers() { if t, ok := layer.(*layers.ICMPv6); ok { if buf, err := toMatchBytes(t.TypeCode); err != nil { return nil, err } else { return buf[1:], nil } } } case oxm.OXM_OF_IPV6_ND_TARGET: for _, layer := range self.Layers() { if t, ok := layer.(*layers.ICMPv6); ok { typ := uint8(t.TypeCode >> 8) if typ == layers.ICMPv6TypeNeighborSolicitation || typ == layers.ICMPv6TypeNeighborAdvertisement { return t.Payload[:16], nil } } } case oxm.OXM_OF_IPV6_ND_SLL: for _, layer := range self.Layers() { if t, ok := layer.(*layers.ICMPv6); ok { typ := uint8(t.TypeCode >> 8) if typ == layers.ICMPv6TypeNeighborSolicitation { for cur := 16; cur < len(t.Payload); { length := int(t.Payload[cur+1]) * 8 if t.Payload[cur] == 1 { // source link-layer address (RFC 2461 4.6) return t.Payload[cur+2 : cur+length], nil } cur += length } } } } case oxm.OXM_OF_IPV6_ND_TLL: for _, layer := range self.Layers() { if t, ok := layer.(*layers.ICMPv6); ok { typ := uint8(t.TypeCode >> 8) if typ == layers.ICMPv6TypeNeighborAdvertisement { for cur := 16; cur < len(t.Payload); { length := int(t.Payload[cur+1]) * 8 if t.Payload[cur] == 2 { // target link-layer address (RFC 2461 4.6) return t.Payload[cur+2 : cur+length], nil } cur += length } } } } case oxm.OXM_OF_MPLS_LABEL: for _, layer := range self.Layers() { if t, ok := layer.(*layers.MPLS); ok { return toMatchBytes(t.Label) } } case oxm.OXM_OF_MPLS_TC: for _, layer := range self.Layers() { if t, ok := layer.(*layers.MPLS); ok { return toMatchBytes(t.TrafficClass) } } case oxm.OXM_OF_MPLS_BOS: for _, layer := range self.Layers() { if t, ok := layer.(*layers.MPLS); ok { var bos uint8 if t.StackBottom { bos = uint8(1) } return toMatchBytes(bos) } } case oxm.OXM_OF_PBB_ISID: for _, layer := range self.Layers() { if t, ok := layer.(*layers2.PBB); ok { ext := make([]byte, 4) binary.BigEndian.PutUint32(ext, t.ServiceIdentifier) return ext[1:], nil } } case oxm.OXM_OF_TUNNEL_ID: return toMatchBytes(self.tunnelId) case oxm.OXM_OF_IPV6_EXTHDR: exthdr := uint16(0) for _, layer := range self.Layers() { switch p := layer.(type) { case *layers.IPv6: if p.NextHeader == layers.IPProtocolNoNextHeader { exthdr |= ofp4.OFPIEH_NONEXT } case *layers.IPSecESP: if exthdr&^(ofp4.OFPIEH_HOP|ofp4.OFPIEH_DEST|ofp4.OFPIEH_ROUTER|ofp4.OFPIEH_FRAG|ofp4.OFPIEH_AUTH) != 0 { exthdr |= ofp4.OFPIEH_UNSEQ } if exthdr&ofp4.OFPIEH_ESP != 0 { exthdr |= ofp4.OFPIEH_UNREP } exthdr |= ofp4.OFPIEH_ESP // if p.NextHeader == layers.IPProtocolNoNextHeader { // exthdr |= ofp4.OFPIEH_NONEXT // } case *layers.IPSecAH: if exthdr&^(ofp4.OFPIEH_HOP|ofp4.OFPIEH_DEST|ofp4.OFPIEH_ROUTER|ofp4.OFPIEH_FRAG) != 0 { exthdr |= ofp4.OFPIEH_UNSEQ } if exthdr&ofp4.OFPIEH_AUTH != 0 { exthdr |= ofp4.OFPIEH_UNREP } exthdr |= ofp4.OFPIEH_AUTH if p.NextHeader == layers.IPProtocolNoNextHeader { exthdr |= ofp4.OFPIEH_NONEXT } case *layers.IPv6Destination: exthdr |= ofp4.OFPIEH_DEST if p.NextHeader == layers.IPProtocolNoNextHeader { exthdr |= ofp4.OFPIEH_NONEXT } case *layers.IPv6Fragment: if exthdr&^(ofp4.OFPIEH_HOP|ofp4.OFPIEH_DEST|ofp4.OFPIEH_ROUTER) != 0 { exthdr |= ofp4.OFPIEH_UNSEQ } if exthdr&ofp4.OFPIEH_FRAG != 0 { exthdr |= ofp4.OFPIEH_UNREP } exthdr |= ofp4.OFPIEH_FRAG if p.NextHeader == layers.IPProtocolNoNextHeader { exthdr |= ofp4.OFPIEH_NONEXT } case *layers.IPv6Routing: if exthdr&^(ofp4.OFPIEH_HOP|ofp4.OFPIEH_DEST) != 0 { exthdr |= ofp4.OFPIEH_UNSEQ } if exthdr&ofp4.OFPIEH_ROUTER != 0 { exthdr |= ofp4.OFPIEH_UNREP } exthdr |= ofp4.OFPIEH_ROUTER if p.NextHeader == layers.IPProtocolNoNextHeader { exthdr |= ofp4.OFPIEH_NONEXT } case *layers.IPv6HopByHop: if exthdr != 0 { exthdr |= ofp4.OFPIEH_UNSEQ } if exthdr&ofp4.OFPIEH_HOP != 0 { exthdr |= ofp4.OFPIEH_UNREP } exthdr |= ofp4.OFPIEH_HOP if p.NextHeader == layers.IPProtocolNoNextHeader { exthdr |= ofp4.OFPIEH_NONEXT } } } return toMatchBytes(exthdr) } return nil, fmt.Errorf("oxm value not found for %d", oxmType) }
func nxmDefs(hdr uint32) (length int, mayMask bool) { switch oxm.Header(hdr).Type() { case NXM_OF_IN_PORT: return 2, false case NXM_OF_ETH_DST: return 6, false case NXM_OF_ETH_SRC: return 6, false case NXM_OF_ETH_TYPE: return 2, false case NXM_OF_VLAN_TCI: return 4, false case NXM_OF_IP_TOS: return 1, false case NXM_OF_IP_PROTO: return 1, false case NXM_OF_IP_SRC: return 4, false case NXM_OF_IP_DST: return 4, false case NXM_OF_TCP_SRC: return 2, false case NXM_OF_TCP_DST: return 2, false case NXM_OF_UDP_SRC: return 2, false case NXM_OF_UDP_DST: return 2, false case NXM_OF_ICMP_TYPE: return 1, false case NXM_OF_ICMP_CODE: return 1, false case NXM_OF_ARP_OP: return 2, false case NXM_OF_ARP_SPA: return 4, false case NXM_OF_ARP_TPA: return 4, false case NXM_NX_REG0: return 4, true case NXM_NX_REG1: return 4, true case NXM_NX_REG2: return 4, true case NXM_NX_REG3: return 4, true case NXM_NX_REG4: return 4, true case NXM_NX_REG5: return 4, true case NXM_NX_REG6: return 4, true case NXM_NX_REG7: return 4, true case NXM_NX_TUN_ID: return 8, true case NXM_NX_ARP_SHA: return 6, true case NXM_NX_ARP_THA: return 6, true case NXM_NX_IPV6_SRC: return 16, true case NXM_NX_IPV6_DST: return 16, true case NXM_NX_ICMPV6_TYPE: return 1, true case NXM_NX_ICMPV6_CODE: return 1, true case NXM_NX_ND_TARGET: return 16, true case NXM_NX_ND_SLL: return 6, true case NXM_NX_ND_TLL: return 6, true case NXM_NX_IP_FRAG: return 1, true case NXM_NX_IPV6_LABEL: return 4, true case NXM_NX_IP_ECN: return 1, true case NXM_NX_IP_TTL: return 1, true case NXM_NX_TUN_IPV4_SRC: return 4, true case NXM_NX_TUN_IPV4_DST: return 4, true case NXM_NX_PKT_MARK: return 4, true case NXM_NX_TCP_FLAGS: return 2, true case NXM_NX_DP_HASH: return 4, true case NXM_NX_RECIRC_ID: return 4, true case NXM_NX_CONJ_ID: return 4, true case NXM_NX_TUN_GBP_ID: return 2, true case NXM_NX_TUN_GBP_FLAGS: return 1, true default: return 0, false } }