func (f Flow) FastHash() (h uint64) {
	h = fnvHash(f.src[:f.slen]) + fnvHash(f.dst[:f.dlen])
	h ^= uint64(f.typ)
	h *= fnvPrime
	return
}
FastHash provides a quick hashing function for a flow, useful if you'd
like to split up flows by modulos or other load-balancing techniques.
It uses a variant of Fowler-Noll-Vo hashing, and is guaranteed to collide
with its reverse flow.  IE: the flow A->B will have the same hash as the flow
B->A.

The output of FastHash is not guaranteed to remain the same through future
code revisions, so should not be used to key values in persistent storage.
package gopacket
import (
	"bytes"
	"fmt"
	"strconv"
)
const MaxEndpointSize = 16
type Endpoint struct {
	typ EndpointType
	len int
	raw [MaxEndpointSize]byte
}
func (a Endpoint) EndpointType() EndpointType { return a.typ }
func (a Endpoint) Raw() []byte { return a.raw[:a.len] }
func (a Endpoint) LessThan(b Endpoint) bool {
	return a.typ < b.typ || (a.typ == b.typ && bytes.Compare(a.raw[:a.len], b.raw[:b.len]) < 0)
}
func fnvHash(s []byte) (h uint64) {
	h = fnvBasis
	for i := 0; i < len(s); i++ {
		h ^= uint64(s[i])
		h *= fnvPrime
	}
	return
}
const fnvBasis = 14695981039346656037
const fnvPrime = 1099511628211
func (a Endpoint) FastHash() (h uint64) {
	h = fnvHash(a.raw[:a.len])
	h ^= uint64(a.typ)
	h *= fnvPrime
	return
}
func NewEndpoint(typ EndpointType, raw []byte) (e Endpoint) {
	e.len = len(raw)
	if e.len > MaxEndpointSize {
		panic("raw byte length greater than MaxEndpointSize")
	}
	e.typ = typ
	copy(e.raw[:], raw)
	return
}
type EndpointTypeMetadata struct {
	Name string
	Formatter func([]byte) string
}
type EndpointType int64
var endpointTypes = map[EndpointType]EndpointTypeMetadata{}
func RegisterEndpointType(num int, meta EndpointTypeMetadata) EndpointType {
	t := EndpointType(num)
	if _, ok := endpointTypes[t]; ok {
		panic("Endpoint type number already in use")
	}
	endpointTypes[t] = meta
	return t
}
func (e EndpointType) String() string {
	if t, ok := endpointTypes[e]; ok {
		return t.Name
	}
	return strconv.Itoa(int(e))
}
func (a Endpoint) String() string {
	if t, ok := endpointTypes[a.typ]; ok && t.Formatter != nil {
		return t.Formatter(a.raw[:a.len])
	}
	return fmt.Sprintf("%v:%v", a.typ, a.raw)
}
type Flow struct {
	typ        EndpointType
	slen, dlen int
	src, dst   [MaxEndpointSize]byte
}
func FlowFromEndpoints(src, dst Endpoint) (_ Flow, err error) {
	if src.typ != dst.typ {
		err = fmt.Errorf("Mismatched endpoint types: %v->%v", src.typ, dst.typ)
		return
	}
	return Flow{src.typ, src.len, dst.len, src.raw, dst.raw}, nil
}