summaryrefslogtreecommitdiffhomepage
path: root/zebra
diff options
context:
space:
mode:
Diffstat (limited to 'zebra')
-rw-r--r--zebra/zapi.go121
-rw-r--r--zebra/zapi_test.go35
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)