diff --git a/bitseq/sequence.go b/bitseq/sequence.go index 09f14ff..ecbf634 100644 --- a/bitseq/sequence.go +++ b/bitseq/sequence.go @@ -5,6 +5,8 @@ package bitseq import ( "fmt" + + "github.com/docker/libnetwork/netutils" ) // Block Sequence constants @@ -74,6 +76,45 @@ func (s *Sequence) Equal(o *Sequence) bool { return true } +// ToByteArray converts the sequence into a byte array +// TODO (aboch): manage network/host order stuff +func (s *Sequence) ToByteArray() ([]byte, error) { + var bb []byte + + p := s + for p != nil { + bb = append(bb, netutils.U32ToA(p.Block)...) + bb = append(bb, netutils.U32ToA(p.Count)...) + p = p.Next + } + + return bb, nil +} + +// FromByteArray construct the sequence from the byte array +// TODO (aboch): manage network/host order stuff +func (s *Sequence) FromByteArray(data []byte) error { + l := len(data) + if l%8 != 0 { + return fmt.Errorf("cannot deserialize byte sequence of lenght %d", l) + } + + p := s + i := 0 + for { + p.Block = netutils.ATo32(data[i : i+4]) + p.Count = netutils.ATo32(data[i+4 : i+8]) + i += 8 + if i == l { + break + } + p.Next = &Sequence{} + p = p.Next + } + + return nil +} + // GetFirstAvailable looks for the first unset bit in passed mask func GetFirstAvailable(head *Sequence) (int, int) { byteIndex := 0 diff --git a/bitseq/sequence_test.go b/bitseq/sequence_test.go index d23d4ac..cebdf43 100644 --- a/bitseq/sequence_test.go +++ b/bitseq/sequence_test.go @@ -331,3 +331,45 @@ func TestPushReservation(t *testing.T) { } } } + +func TestSerializeDeserialize(t *testing.T) { + s := &Sequence{ + Block: 0xffffffff, + Count: 1, + Next: &Sequence{ + Block: 0xFF000000, + Count: 1, + Next: &Sequence{ + Block: 0xffffffff, + Count: 6, + Next: &Sequence{ + Block: 0xffffffff, + Count: 1, + Next: &Sequence{ + Block: 0xFF800000, + Count: 1, + Next: &Sequence{ + Block: 0xffffffff, + Count: 6, + }, + }, + }, + }, + }, + } + + data, err := s.ToByteArray() + if err != nil { + t.Fatal(err) + } + + r := &Sequence{} + err = r.FromByteArray(data) + if err != nil { + t.Fatal(err) + } + + if !s.Equal(r) { + t.Fatalf("Sequences are different: \n%v\n%v", s, r) + } +} diff --git a/netutils/utils.go b/netutils/utils.go index 222b7a2..0ef357e 100644 --- a/netutils/utils.go +++ b/netutils/utils.go @@ -168,3 +168,53 @@ func GenerateIfaceName(prefix string, len int) (string, error) { } return "", types.InternalErrorf("could not generate interface name") } + +func byteArrayToInt(array []byte, numBytes int) uint64 { + if numBytes <= 0 || numBytes > 8 { + panic("Invalid argument") + } + num := 0 + for i := 0; i <= len(array)-1; i++ { + num += int(array[len(array)-1-i]) << uint(i*8) + } + return uint64(num) +} + +// ATo64 converts a byte array into a uint32 +func ATo64(array []byte) uint64 { + return byteArrayToInt(array, 8) +} + +// ATo32 converts a byte array into a uint32 +func ATo32(array []byte) uint32 { + return uint32(byteArrayToInt(array, 4)) +} + +// ATo16 converts a byte array into a uint16 +func ATo16(array []byte) uint16 { + return uint16(byteArrayToInt(array, 2)) +} + +func intToByteArray(val uint64, numBytes int) []byte { + array := make([]byte, numBytes) + for i := numBytes - 1; i >= 0; i-- { + array[i] = byte(val & 0xff) + val = val >> 8 + } + return array +} + +// U64ToA converts a uint64 to a byte array +func U64ToA(val uint64) []byte { + return intToByteArray(uint64(val), 8) +} + +// U32ToA converts a uint64 to a byte array +func U32ToA(val uint32) []byte { + return intToByteArray(uint64(val), 4) +} + +// U16ToA converts a uint64 to a byte array +func U16ToA(val uint16) []byte { + return intToByteArray(uint64(val), 2) +}