diff options
author | IWASE Yusuke <iwase.yusuke0@gmail.com> | 2017-02-14 14:45:27 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2017-02-15 00:11:29 +0900 |
commit | c0d521333f7be469e4b90877475e8fcb1333acef (patch) | |
tree | 84fa9b6de378b86afdd7863a8958ce2d1516d4b3 | |
parent | 087ea7585069481bc0cf45f658698cc3ef9f5a3e (diff) |
zebra/zapi: Support NEXTHOP_REGISTER message
Signed-off-by: IWASE Yusuke <iwase.yusuke0@gmail.com>
-rw-r--r-- | zebra/zapi.go | 121 | ||||
-rw-r--r-- | zebra/zapi_test.go | 35 |
2 files changed, 156 insertions, 0 deletions
diff --git a/zebra/zapi.go b/zebra/zapi.go index 69a1d2f4..e967eaf6 100644 --- a/zebra/zapi.go +++ b/zebra/zapi.go @@ -1026,6 +1026,127 @@ func (b *ImportLookupBody) String() string { return s } +type RegisteredNexthop struct { + Connected uint8 + Family uint16 + // Note: Ignores PrefixLength (uint8), + // because this field should be always: + // - 32 if Address Family is AF_INET + // - 128 if Address Family is AF_INET6 + Prefix net.IP +} + +func (n *RegisteredNexthop) Len() int { + // Connected (1 byte) + Address Family (2 bytes) + Prefix Length (1 byte) + Prefix (variable) + if n.Family == uint16(syscall.AF_INET) { + return 4 + net.IPv4len + } else { + return 4 + net.IPv6len + } +} + +func (n *RegisteredNexthop) Serialize() ([]byte, error) { + // Connected (1 byte) + buf := make([]byte, 4) + buf[0] = byte(n.Connected) + + // Address Family (2 bytes) + binary.BigEndian.PutUint16(buf[1:3], n.Family) + + // Prefix Length (1 byte) + Prefix (variable) + switch n.Family { + case uint16(syscall.AF_INET): + buf[3] = byte(net.IPv4len * 8) + buf = append(buf, n.Prefix.To4()...) + case uint16(syscall.AF_INET6): + buf[3] = byte(net.IPv6len * 8) + buf = append(buf, n.Prefix.To16()...) + default: + return nil, fmt.Errorf("invalid address family: %d", n.Family) + } + + return buf, nil +} + +func (n *RegisteredNexthop) DecodeFromBytes(data []byte) error { + // Connected (1 byte) + n.Connected = uint8(data[0]) + offset := 1 + + // Address Family (2 bytes) + n.Family = binary.BigEndian.Uint16(data[offset : offset+2]) + isV4 := n.Family == uint16(syscall.AF_INET) + addrLen := int(net.IPv4len) + if !isV4 { + addrLen = net.IPv6len + } + // Note: Ignores Prefix Length (1 byte) + offset += 3 + + // Prefix (variable) + if isV4 { + n.Prefix = net.IP(data[offset : offset+addrLen]).To4() + } else { + n.Prefix = net.IP(data[offset : offset+addrLen]).To16() + } + + return nil +} + +func (n *RegisteredNexthop) String() string { + return fmt.Sprintf("connected: %d, family: %d, prefix: %s", n.Connected, n.Family, n.Prefix.String()) +} + +type NexthopRegisterBody struct { + Api API_TYPE + Nexthops []*RegisteredNexthop +} + +func (b *NexthopRegisterBody) Serialize() ([]byte, error) { + buf := make([]byte, 0) + + // List of Registered Nexthops + for _, nh := range b.Nexthops { + nhBuf, err := nh.Serialize() + if err != nil { + return nil, err + } + buf = append(buf, nhBuf...) + } + + return buf, nil +} + +func (b *NexthopRegisterBody) DecodeFromBytes(data []byte, version uint8) error { + offset := 0 + + // List of Registered Nexthops + b.Nexthops = []*RegisteredNexthop{} + for len(data[offset:]) > 0 { + nh := new(RegisteredNexthop) + err := nh.DecodeFromBytes(data[offset:]) + if err != nil { + return err + } + b.Nexthops = append(b.Nexthops, nh) + + offset += nh.Len() + if len(data) < offset { + break + } + } + + return nil +} + +func (b *NexthopRegisterBody) String() string { + s := make([]string, 0) + for _, nh := range b.Nexthops { + s = append(s, fmt.Sprintf("nexthop:{%s}", nh.String())) + } + return strings.Join(s, ", ") +} + type NexthopUpdateBody struct { Api API_TYPE Family uint16 diff --git a/zebra/zapi_test.go b/zebra/zapi_test.go index 7d0fe29b..5fcdbcc6 100644 --- a/zebra/zapi_test.go +++ b/zebra/zapi_test.go @@ -452,6 +452,41 @@ func Test_ImportLookupBody(t *testing.T) { assert.NotEqual(nil, err) } +func Test_NexthopRegisterBody(t *testing.T) { + assert := assert.New(t) + + // Input binary + bufIn := []byte{ + 0x01, 0x00, 0x02, 0x20, // connected(1 byte)=1, afi(2 bytes)=AF_INET, prefix_len(1 byte)=32 + 0xc0, 0xa8, 0x01, 0x01, // prefix(4 bytes)="192.168.1.1" + 0x00, 0x00, 0x0a, 0x80, // connected(1 byte)=0, afi(2 bytes)=AF_INET6, prefix_len(1 byte)=128 + 0x20, 0x01, 0x0d, 0xb8, // prefix(16 bytes)="2001:db8:1:1::1" + 0x00, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, + } + + // Test DecodeFromBytes() + b := &NexthopRegisterBody{Api: NEXTHOP_REGISTER} + err := b.DecodeFromBytes(bufIn, 3) + assert.Nil(err) + + // Test decoded values + assert.Equal(uint8(1), b.Nexthops[0].Connected) + assert.Equal(uint16(syscall.AF_INET), b.Nexthops[0].Family) + assert.Equal(net.ParseIP("192.168.1.1").To4(), b.Nexthops[0].Prefix) + assert.Equal(uint8(0), b.Nexthops[1].Connected) + assert.Equal(uint16(syscall.AF_INET6), b.Nexthops[1].Family) + assert.Equal(net.ParseIP("2001:db8:1:1::1").To16(), b.Nexthops[1].Prefix) + + // Test Serialize() + bufOut, err := b.Serialize() + assert.Nil(err) + + // Test serialised value + assert.Equal(bufIn, bufOut) +} + func Test_NexthopUpdateBody(t *testing.T) { assert := assert.New(t) |