zebra/zapi: Support NEXTHOP_UPDATE message

Signed-off-by: IWASE Yusuke <[email protected]>
This commit is contained in:
IWASE Yusuke
2017-02-15 00:11:29 +09:00
committed by FUJITA Tomonori
parent 0e53acd88f
commit 087ea75850
2 changed files with 143 additions and 0 deletions
+110
View File
@@ -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)
}
+33
View File
@@ -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])
}