summaryrefslogtreecommitdiffhomepage
path: root/zebra
diff options
context:
space:
mode:
authorIWASE Yusuke <iwase.yusuke0@gmail.com>2017-02-10 14:34:24 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2017-02-15 00:11:29 +0900
commit087ea7585069481bc0cf45f658698cc3ef9f5a3e (patch)
tree58dc04b7559c295655491a6cf47b804cf355ee5d /zebra
parent0e53acd88f3389d4dbade900abe783ae68faf292 (diff)
zebra/zapi: Support NEXTHOP_UPDATE message
Signed-off-by: IWASE Yusuke <iwase.yusuke0@gmail.com>
Diffstat (limited to 'zebra')
-rw-r--r--zebra/zapi.go110
-rw-r--r--zebra/zapi_test.go33
2 files changed, 143 insertions, 0 deletions
diff --git a/zebra/zapi.go b/zebra/zapi.go
index 0b525e60..69a1d2f4 100644
--- a/zebra/zapi.go
+++ b/zebra/zapi.go
@@ -1026,6 +1026,111 @@ func (b *ImportLookupBody) String() string {
return s
}
+type NexthopUpdateBody struct {
+ Api API_TYPE
+ 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
+ Metric uint32
+ Nexthops []*Nexthop
+}
+
+func (b *NexthopUpdateBody) Serialize() ([]byte, error) {
+ // Address Family (2 bytes)
+ buf := make([]byte, 3)
+ binary.BigEndian.PutUint16(buf, b.Family)
+
+ // Prefix Length (1 byte) + Prefix (variable)
+ switch b.Family {
+ case uint16(syscall.AF_INET):
+ buf[2] = byte(net.IPv4len * 8)
+ buf = append(buf, b.Prefix.To4()...)
+ case uint16(syscall.AF_INET6):
+ buf[2] = byte(net.IPv6len * 8)
+ buf = append(buf, b.Prefix.To16()...)
+ default:
+ return nil, fmt.Errorf("invalid address family: %d", b.Family)
+ }
+
+ return buf, nil
+}
+
+func (b *NexthopUpdateBody) DecodeFromBytes(data []byte, version uint8) error {
+ // Address Family (2 bytes)
+ b.Family = binary.BigEndian.Uint16(data[0:2])
+ isV4 := b.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 {
+ b.Prefix = net.IP(data[offset : offset+addrLen]).To4()
+ } else {
+ b.Prefix = net.IP(data[offset : offset+addrLen]).To16()
+ }
+ offset += addrLen
+
+ // Metric (4 bytes)
+ // Number of Nexthops (1 byte)
+ if len(data[offset:]) < 4+1 {
+ return fmt.Errorf("invalid message length: missing metric(4 bytes) or nexthops(1 byte): %d<5", len(data[offset:]))
+ }
+ b.Metric = binary.BigEndian.Uint32(data[offset : offset+4])
+ offset += 4
+ nexthopsNum := int(data[offset])
+ offset += 1
+
+ // List of Nexthops
+ b.Nexthops = []*Nexthop{}
+ for i := 0; i < nexthopsNum; i++ {
+ nh := &Nexthop{}
+ nh.Type = NEXTHOP_FLAG(data[offset])
+ offset += 1
+
+ switch nh.Type {
+ case NEXTHOP_IPV4, NEXTHOP_IPV6:
+ if isV4 {
+ nh.Addr = net.IP(data[offset : offset+addrLen]).To4()
+ } else {
+ nh.Addr = net.IP(data[offset : offset+addrLen]).To16()
+ }
+ offset += addrLen
+
+ case NEXTHOP_IPV4_IFINDEX, NEXTHOP_IPV4_IFNAME, NEXTHOP_IPV6_IFINDEX, NEXTHOP_IPV6_IFNAME:
+ if isV4 {
+ nh.Addr = net.IP(data[offset : offset+addrLen]).To4()
+ } else {
+ nh.Addr = net.IP(data[offset : offset+addrLen]).To16()
+ }
+ offset += addrLen
+ nh.Ifindex = binary.BigEndian.Uint32(data[offset : offset+4])
+ offset += 4
+
+ case NEXTHOP_IFINDEX, NEXTHOP_IFNAME:
+ nh.Ifindex = binary.BigEndian.Uint32(data[offset : offset+4])
+ offset += 4
+ }
+ b.Nexthops = append(b.Nexthops, nh)
+ }
+
+ return nil
+}
+
+func (b *NexthopUpdateBody) String() string {
+ s := fmt.Sprintf("family: %d, prefix: %s, metric: %d", b.Family, b.Prefix.String(), b.Metric)
+ for _, nh := range b.Nexthops {
+ s = s + fmt.Sprintf(", nexthop:{%s}", nh.String())
+ }
+ return s
+}
+
type Message struct {
Header Header
Body Body
@@ -1073,6 +1178,11 @@ func ParseMessage(hdr *Header, data []byte) (*Message, error) {
log.WithFields(log.Fields{
"Topic": "Zebra",
}).Debugf("ipv4 import lookup message received: %v", data)
+ case NEXTHOP_UPDATE:
+ m.Body = &NexthopUpdateBody{Api: m.Header.Command}
+ log.WithFields(log.Fields{
+ "Topic": "Zebra",
+ }).Debugf("nexthop update message received: %v", data)
default:
return nil, fmt.Errorf("Unknown zapi command: %d", m.Header.Command)
}
diff --git a/zebra/zapi_test.go b/zebra/zapi_test.go
index ac4862f0..7d0fe29b 100644
--- a/zebra/zapi_test.go
+++ b/zebra/zapi_test.go
@@ -19,6 +19,7 @@ import (
"encoding/binary"
"github.com/stretchr/testify/assert"
"net"
+ "syscall"
"testing"
)
@@ -450,3 +451,35 @@ func Test_ImportLookupBody(t *testing.T) {
err = b.DecodeFromBytes(buf, 2)
assert.NotEqual(nil, err)
}
+
+func Test_NexthopUpdateBody(t *testing.T) {
+ assert := assert.New(t)
+
+ // Input binary
+ bufIn := []byte{
+ 0x00, 0x02, 0x20, // afi(2 bytes)=AF_INET, prefix_len(1 byte)=32
+ 0xc0, 0xa8, 0x01, 0x01, // prefix(4 bytes)="192.168.1.1"
+ 0x00, 0x00, 0x00, 0x01, // metric(4 bytes)=1
+ 0x01, // nexthops(1 byte)=1
+ 0x04, // nexthop_type(1 byte)=NEXTHOP_IPV4_IFINDEX
+ 0xc0, 0xa8, 0x01, 0x01, // nexthop_ip(4 bytes)="192.168.0.1"
+ 0x00, 0x00, 0x00, 0x02, // nexthop_ifindex(4 byte)=2
+ }
+
+ // Test DecodeFromBytes()
+ b := &NexthopUpdateBody{Api: NEXTHOP_UPDATE}
+ err := b.DecodeFromBytes(bufIn, 2)
+ assert.Nil(err)
+
+ // Test decoded values
+ assert.Equal(uint16(syscall.AF_INET), b.Family)
+ assert.Equal(net.ParseIP("192.168.1.1").To4(), b.Prefix)
+ assert.Equal(uint32(1), b.Metric)
+ nexthop := &Nexthop{
+ Type: NEXTHOP_FLAG(NEXTHOP_IPV4_IFINDEX),
+ Addr: net.ParseIP("192.168.1.1").To4(),
+ Ifindex: uint32(2),
+ }
+ assert.Equal(1, len(b.Nexthops))
+ assert.Equal(nexthop, b.Nexthops[0])
+}