summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorHiroshi Yokoi <yokoi.hiroshi@po.ntts.co.jp>2015-08-26 18:11:38 +0900
committerHiroshi Yokoi <yokoi.hiroshi@po.ntts.co.jp>2015-09-01 19:42:02 +0900
commitcc51c48a4934bde8f5a5555632633c3c8486b797 (patch)
tree14998dac3531e6a609bb414d2816f7f7d2ba1d5f
parentf8d437ec0ea65656ca4c6d81ec48fe0f7099c60e (diff)
zebra: distribute routes from zebra
Signed-off-by: Hiroshi Yokoi <yokoi.hiroshi@po.ntts.co.jp>
-rw-r--r--server/server.go22
-rw-r--r--server/zclient.go63
-rw-r--r--server/zclient_test.go104
-rw-r--r--table/destination.go2
-rw-r--r--table/path.go1
-rw-r--r--zebra/zapi.go149
-rw-r--r--zebra/zapi_test.go320
7 files changed, 640 insertions, 21 deletions
diff --git a/server/server.go b/server/server.go
index 92e3d178..971cc517 100644
--- a/server/server.go
+++ b/server/server.go
@@ -231,7 +231,10 @@ func (server *BgpServer) Serve() {
case rmsg := <-server.roaClient.recieveROA():
server.roaClient.handleRTRMsg(rmsg)
case zmsg := <-zapiMsgCh:
- handleZapiMsg(zmsg)
+ m := handleZapiMsg(zmsg, server)
+ if len(m) > 0 {
+ senderMsgs = append(senderMsgs, m...)
+ }
case conn := <-acceptCh:
remoteAddr, _, _ := net.SplitHostPort(conn.RemoteAddr().String())
peer, found := server.neighborMap[remoteAddr]
@@ -548,9 +551,16 @@ func applyPolicies(peer *Peer, loc *LocalRib, d Direction, pathList []*table.Pat
func (server *BgpServer) broadcastBests(bests []*table.Path) {
for _, path := range bests {
- z := newBroadcastZapiBestMsg(server.zclient, path)
- if z != nil {
- server.broadcastMsgs = append(server.broadcastMsgs, z)
+ if !path.IsFromZebra {
+ z := newBroadcastZapiBestMsg(server.zclient, path)
+ if z != nil {
+ server.broadcastMsgs = append(server.broadcastMsgs, z)
+ log.WithFields(log.Fields{
+ "Topic": "Server",
+ "Client": z.client,
+ "Message": z.msg,
+ }).Debug("Default policy applied and rejected.")
+ }
}
result := &GrpcResponse{
@@ -654,6 +664,7 @@ func (server *BgpServer) propagateUpdate(peer *Peer, pathList []*table.Path) []*
}
targetPeer.adjRib.UpdateOut(f)
msgList := table.CreateUpdateMsgFromPaths(f)
+
msgs = append(msgs, newSenderMsg(targetPeer, msgList))
}
}
@@ -2322,6 +2333,9 @@ func (server *BgpServer) NewZclient(url string) error {
return err
}
cli.SendHello()
+ cli.SendRouterIDAdd()
+ cli.SendInterfaceAdd()
+ cli.SendRedistribute()
server.zclient = cli
return nil
}
diff --git a/server/zclient.go b/server/zclient.go
index 7c1b9a42..ab163b37 100644
--- a/server/zclient.go
+++ b/server/zclient.go
@@ -16,12 +16,14 @@
package server
import (
+ log "github.com/Sirupsen/logrus"
"github.com/osrg/gobgp/packet"
"github.com/osrg/gobgp/table"
"github.com/osrg/gobgp/zebra"
"net"
"strconv"
"strings"
+ "time"
)
type broadcastZapiMsg struct {
@@ -84,6 +86,49 @@ func newIPRouteMessage(path *table.Path) *zebra.Message {
}
}
+func createPathFromIPRouteMessage(m *zebra.Message, peerInfo *table.PeerInfo) *table.Path {
+
+ header := m.Header
+ body := m.Body.(*zebra.IPRouteBody)
+ isV4 := header.Command == zebra.IPV4_ROUTE_ADD || header.Command == zebra.IPV4_ROUTE_DELETE
+
+ var nlri bgp.AddrPrefixInterface
+ pattr := make([]bgp.PathAttributeInterface, 0)
+ var mpnlri *bgp.PathAttributeMpReachNLRI
+ var isWithdraw bool = header.Command == zebra.IPV4_ROUTE_DELETE || header.Command == zebra.IPV6_ROUTE_DELETE
+
+ origin := bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_IGP)
+ pattr = append(pattr, origin)
+
+ log.WithFields(log.Fields{
+ "Topic": "Zebra",
+ "RouteType": body.Type.String(),
+ "Flag": body.Flags.String(),
+ "Message": body.Message,
+ "Prefix": body.Prefix,
+ "PrefixLength": body.PrefixLength,
+ "Nexthop": body.Nexthops,
+ "api": header.Command.String(),
+ }).Debugf("create path from ip route message.")
+
+ if isV4 {
+ nlri = bgp.NewNLRInfo(body.PrefixLength, body.Prefix.String())
+ nexthop := bgp.NewPathAttributeNextHop("0.0.0.0")
+ pattr = append(pattr, nexthop)
+ } else {
+ nlri = bgp.NewIPv6AddrPrefix(body.PrefixLength, body.Prefix.String())
+ mpnlri = bgp.NewPathAttributeMpReachNLRI("::", []bgp.AddrPrefixInterface{nlri})
+ pattr = append(pattr, mpnlri)
+ }
+
+ med := bgp.NewPathAttributeMultiExitDisc(body.Metric)
+ pattr = append(pattr, med)
+
+ p := table.NewPath(peerInfo, nlri, isWithdraw, pattr, false, time.Now(), true)
+ p.IsFromZebra = true
+ return p
+}
+
func newBroadcastZapiBestMsg(cli *zebra.Client, path *table.Path) *broadcastZapiMsg {
if cli == nil {
return nil
@@ -98,5 +143,21 @@ func newBroadcastZapiBestMsg(cli *zebra.Client, path *table.Path) *broadcastZapi
}
}
-func handleZapiMsg(msg *zebra.Message) {
+func handleZapiMsg(msg *zebra.Message, server *BgpServer) []*SenderMsg {
+
+ switch b := msg.Body.(type) {
+ case *zebra.IPRouteBody:
+ pi := &table.PeerInfo{
+ AS: server.bgpConfig.Global.GlobalConfig.As,
+ LocalID: server.bgpConfig.Global.GlobalConfig.RouterId,
+ }
+
+ if b.Prefix != nil && len(b.Nexthops) > 0 && b.Type != zebra.ROUTE_KERNEL {
+ p := createPathFromIPRouteMessage(msg, pi)
+ msgs := server.propagateUpdate("", false, []*table.Path{p})
+ return msgs
+ }
+ }
+
+ return nil
}
diff --git a/server/zclient_test.go b/server/zclient_test.go
new file mode 100644
index 00000000..257a1d06
--- /dev/null
+++ b/server/zclient_test.go
@@ -0,0 +1,104 @@
+// Copyright (C) 2014 Nippon Telegraph and Telephone Corporation.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+// implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package server
+import (
+ "github.com/stretchr/testify/assert"
+ "github.com/osrg/gobgp/zebra"
+ "github.com/osrg/gobgp/table"
+ "testing"
+ "net"
+)
+
+func Test_createPathFromIPRouteMessage(t *testing.T) {
+ assert := assert.New(t)
+
+ m := &zebra.Message{}
+ h := &zebra.Header{
+ Len: zebra.HEADER_SIZE,
+ Marker: zebra.HEADER_MARKER,
+ Version: zebra.VERSION,
+ Command: zebra.IPV4_ROUTE_ADD,
+ }
+
+ b := &zebra.IPRouteBody{
+ Type: zebra.ROUTE_TYPE(zebra.ROUTE_STATIC),
+ Flags: zebra.FLAG(zebra.FLAG_SELECTED),
+ Message: zebra.MESSAGE_NEXTHOP | zebra.MESSAGE_DISTANCE | zebra.MESSAGE_METRIC,
+ SAFI: zebra.SAFI(zebra.SAFI_UNICAST),
+ Prefix: net.ParseIP("192.168.100.0"),
+ PrefixLength :uint8(24),
+ Nexthops : []net.IP{net.ParseIP("0.0.0.0")},
+ Ifindexs : []uint32{1},
+ Distance: uint8(0),
+ Metric : uint32(100),
+ Api : zebra.API_TYPE(zebra.IPV4_ROUTE_ADD),
+ }
+
+ m.Header = *h
+ m.Body = b
+
+ pi := &table.PeerInfo{
+ AS: 65000,
+ LocalID: net.ParseIP("10.0.0.1"),
+ }
+ p := createPathFromIPRouteMessage(m, pi)
+ assert.NotEqual(nil, p)
+ assert.Equal("0.0.0.0", p.GetNexthop().String())
+ assert.Equal("192.168.100.0/24",p.GetNlri().String())
+ assert.True(p.IsFromZebra)
+ assert.False(p.IsWithdraw)
+
+ // withdraw
+ h.Command = zebra.IPV4_ROUTE_DELETE
+ m.Header = *h
+ p = createPathFromIPRouteMessage(m, pi)
+ assert.NotEqual(nil, p)
+ assert.Equal("0.0.0.0", p.GetNexthop().String())
+ assert.Equal("192.168.100.0/24",p.GetNlri().String())
+ med, _ := p.GetMed()
+ assert.Equal(uint32(100), med)
+ assert.True(p.IsFromZebra)
+ assert.True(p.IsWithdraw)
+
+
+ // IPv6
+ h.Command = zebra.IPV6_ROUTE_ADD
+ b.Prefix = net.ParseIP("2001:db8:0:f101::")
+ b.PrefixLength = uint8(64)
+ b.Nexthops = []net.IP{net.ParseIP("::")}
+ m.Header = *h
+ m.Body = b
+
+ p = createPathFromIPRouteMessage(m, pi)
+ assert.NotEqual(nil, p)
+ assert.Equal("::", p.GetNexthop().String())
+ assert.Equal("2001:db8:0:f101::/64",p.GetNlri().String())
+ med, _ = p.GetMed()
+ assert.Equal(uint32(100), med)
+ assert.True(p.IsFromZebra)
+ assert.False(p.IsWithdraw)
+
+ // withdraw
+ h.Command = zebra.IPV6_ROUTE_DELETE
+ m.Header = *h
+ p = createPathFromIPRouteMessage(m, pi)
+ assert.NotEqual(nil, p)
+ assert.Equal("::", p.GetNexthop().String())
+ assert.Equal("2001:db8:0:f101::/64",p.GetNlri().String())
+ assert.True(p.IsFromZebra)
+ assert.True(p.IsWithdraw)
+
+} \ No newline at end of file
diff --git a/table/destination.go b/table/destination.go
index 5889fb5b..de2bf659 100644
--- a/table/destination.go
+++ b/table/destination.go
@@ -613,7 +613,7 @@ func compareByASPath(path1, path2 *Path) *Path {
"Key": "compareByASPath",
"ASPath1": attribute1,
"ASPath2": attribute2,
- }).Error("can't compare ASPath because it's not present")
+ }).Warn("can't compare ASPath because it's not present")
}
l1 := path1.GetAsPathLen()
diff --git a/table/path.go b/table/path.go
index 6dbb1f24..eba3340a 100644
--- a/table/path.go
+++ b/table/path.go
@@ -37,6 +37,7 @@ type Path struct {
timestamp time.Time
NoImplicitWithdraw bool
Validation config.RpkiValidationResultType
+ IsFromZebra bool
}
func NewPath(source *PeerInfo, nlri bgp.AddrPrefixInterface, isWithdraw bool, pattrs []bgp.PathAttributeInterface, medSetByTargetNeighbor bool, timestamp time.Time, noImplicitWithdraw bool) *Path {
diff --git a/zebra/zapi.go b/zebra/zapi.go
index c014531c..08fcf80d 100644
--- a/zebra/zapi.go
+++ b/zebra/zapi.go
@@ -226,7 +226,7 @@ func NewClient(network, address string, typ ROUTE_TYPE) (*Client, error) {
log.Error("failed to read header: ", err)
return err
}
-
+ log.Debugf("read header from zebra: %v", headerBuf)
hd := &Header{}
err = hd.DecodeFromBytes(headerBuf)
if err != nil {
@@ -239,7 +239,7 @@ func NewClient(network, address string, typ ROUTE_TYPE) (*Client, error) {
log.Error("failed to read body: ", err)
return err
}
-
+ log.Debugf("read body from zebra: %v", bodyBuf)
m, err := ParseMessage(hd, bodyBuf)
if err != nil {
log.Warn("failed to parse message: ", err)
@@ -272,6 +272,12 @@ func (c *Client) Send(m *Message) {
}
func (c *Client) SendCommand(command API_TYPE, body Body) error {
+
+ log.WithFields(log.Fields{
+ "Topic": "Zebra",
+ "Command": command.String(),
+ "Body": body,
+ }).Debug("send command to zebra")
m := &Message{
Header: Header{
Len: HEADER_SIZE,
@@ -288,7 +294,7 @@ func (c *Client) SendCommand(command API_TYPE, body Body) error {
func (c *Client) SendHello() error {
if c.redistDefault > 0 {
body := &HelloBody{
- Redist: c.redistDefault,
+ RedistDefault: c.redistDefault,
}
return c.SendCommand(HELLO, body)
}
@@ -303,6 +309,24 @@ func (c *Client) SendInterfaceAdd() error {
return c.SendCommand(INTERFACE_ADD, nil)
}
+func (c *Client) SendRedistribute() error {
+ for i := ROUTE_SYSTEM; i < ROUTE_MAX; i++ {
+ if c.redistDefault != i {
+ body := &RedistributeBody{
+ Redist: i,
+ }
+ if e := c.SendCommand(REDISTRIBUTE_ADD, body); e != nil {
+ return e
+ }
+ }
+ }
+
+ if e := c.SendCommand(REDISTRIBUTE_DEFAULT_ADD, nil); e != nil {
+ return e
+ }
+ return nil
+}
+
func (c *Client) Close() error {
close(c.outgoing)
return c.conn.Close()
@@ -341,15 +365,28 @@ type Body interface {
}
type HelloBody struct {
- Redist ROUTE_TYPE
+ RedistDefault ROUTE_TYPE
}
func (b *HelloBody) DecodeFromBytes(data []byte) error {
- b.Redist = ROUTE_TYPE(data[0])
+ b.RedistDefault = ROUTE_TYPE(data[0])
return nil
}
func (b *HelloBody) Serialize() ([]byte, error) {
+ return []byte{uint8(b.RedistDefault)}, nil
+}
+
+type RedistributeBody struct {
+ Redist ROUTE_TYPE
+}
+
+func (b *RedistributeBody) DecodeFromBytes(data []byte) error {
+ b.Redist = ROUTE_TYPE(data[0])
+ return nil
+}
+
+func (b *RedistributeBody) Serialize() ([]byte, error) {
return []byte{uint8(b.Redist)}, nil
}
@@ -471,16 +508,7 @@ type IPRouteBody struct {
Ifindexs []uint32
Distance uint8
Metric uint32
-}
-
-func (b *IPRouteBody) DecodeFromBytes(data []byte) error {
- b.Type = ROUTE_TYPE(data[0])
- b.Flags = FLAG(data[1])
- b.Message = data[2]
- b.SAFI = SAFI(data[3])
- b.Prefix = data[3:7]
- b.PrefixLength = data[7]
- return nil
+ Api API_TYPE
}
func (b *IPRouteBody) Serialize() ([]byte, error) {
@@ -537,6 +565,94 @@ func (b *IPRouteBody) Serialize() ([]byte, error) {
return buf, nil
}
+func (b *IPRouteBody) DecodeFromBytes(data []byte) error {
+
+ isV4 := b.Api == IPV4_ROUTE_ADD || b.Api == IPV4_ROUTE_DELETE
+ var addrLen uint8 = net.IPv4len
+ if !isV4 {
+ addrLen = net.IPv6len
+ }
+
+ b.Type = ROUTE_TYPE(data[0])
+ b.Flags = FLAG(data[1])
+ b.Message = data[2]
+ b.PrefixLength = data[3]
+ b.SAFI = SAFI(SAFI_UNICAST)
+
+ if b.PrefixLength > addrLen*8 {
+ return fmt.Errorf("prefix length is greater than %d", addrLen*8)
+ }
+
+ byteLen := int((b.PrefixLength + 7) / 8)
+
+ curPos := 4
+ buf := make([]byte, addrLen)
+ copy(buf, data[curPos:curPos+byteLen])
+
+ if isV4 {
+ b.Prefix = net.IP(buf).To4()
+ } else {
+ b.Prefix = net.IP(buf).To16()
+ }
+
+ curPos += byteLen
+
+ rest := 0
+ var numNexthop int
+ if b.Message&MESSAGE_NEXTHOP > 0 {
+ numNexthop = int(data[curPos])
+ // rest = numNexthop(1) + (nexthop(4 or 16) + placeholder(1) + ifindex(4)) * numNexthop
+ rest += 1 + numNexthop*(int(addrLen)+5)
+ }
+
+ if b.Message&MESSAGE_DISTANCE > 0 {
+ // distance(1)
+ rest += 1
+ }
+
+ if b.Message&MESSAGE_METRIC > 0 {
+ // metric(4)
+ rest += 4
+ }
+
+ if len(data[curPos:]) != rest {
+ return fmt.Errorf("message length invalid")
+ }
+
+ b.Nexthops = []net.IP{}
+ b.Ifindexs = []uint32{}
+
+ if b.Message&MESSAGE_NEXTHOP > 0 {
+ curPos += 1
+ for i := 0; i < numNexthop; i++ {
+ addr := data[curPos : curPos+int(addrLen)]
+ var nexthop net.IP
+ if isV4 {
+ nexthop = net.IP(addr).To4()
+ } else {
+ nexthop = net.IP(addr).To16()
+ }
+ b.Nexthops = append(b.Nexthops, nexthop)
+
+ // skip nexthop and 1byte place holder
+ curPos += int(addrLen + 1)
+ ifidx := binary.BigEndian.Uint32(data[curPos : curPos+4])
+ b.Ifindexs = append(b.Ifindexs, ifidx)
+ curPos += 4
+ }
+ }
+
+ if b.Message&MESSAGE_DISTANCE > 0 {
+ b.Distance = data[curPos]
+ }
+ if b.Message&MESSAGE_METRIC > 0 {
+ curPos += 1
+ b.Metric = binary.BigEndian.Uint32(data[curPos : curPos+4])
+ }
+
+ return nil
+}
+
type Message struct {
Header Header
Body Body
@@ -569,6 +685,9 @@ func ParseMessage(hdr *Header, data []byte) (*Message, error) {
m.Body = &InterfaceAddressUpdateBody{}
case ROUTER_ID_UPDATE:
m.Body = &RouterIDUpdateBody{}
+ case IPV4_ROUTE_ADD, IPV6_ROUTE_ADD, IPV4_ROUTE_DELETE, IPV6_ROUTE_DELETE:
+ m.Body = &IPRouteBody{Api: m.Header.Command}
+ log.Debugf("ipv4/v6 route add/delete 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
new file mode 100644
index 00000000..fcb912a1
--- /dev/null
+++ b/zebra/zapi_test.go
@@ -0,0 +1,320 @@
+// Copyright (C) 2014, 2015 Nippon Telegraph and Telephone Corporation.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+// implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package zebra
+
+import (
+ "encoding/binary"
+ "github.com/stretchr/testify/assert"
+ "net"
+ "testing"
+)
+
+func Test_Header(t *testing.T) {
+ assert := assert.New(t)
+
+ //DecodeFromBytes
+ buf := make([]byte, 6)
+ binary.BigEndian.PutUint16(buf[0:], 10)
+ buf[2] = HEADER_MARKER
+ buf[3] = VERSION
+ binary.BigEndian.PutUint16(buf[4:], uint16(IPV4_ROUTE_ADD))
+ h := &Header{}
+ err := h.DecodeFromBytes(buf)
+ assert.Equal(nil, err)
+
+ //Serialize
+ buf, err = h.Serialize()
+ assert.Equal(nil, err)
+ h2 := &Header{}
+ err = h2.DecodeFromBytes(buf)
+ assert.Equal(nil, err)
+ assert.Equal(h, h2)
+
+ // header_size mismatch
+ buf = make([]byte, HEADER_SIZE-1)
+ binary.BigEndian.PutUint16(buf[0:], 10)
+ buf[2] = 0xff
+ buf[3] = 0x02
+ h3 := &Header{}
+ err = h3.DecodeFromBytes(buf)
+ assert.NotEqual(nil, err)
+}
+
+func Test_InterfaceUpdateBody(t *testing.T) {
+ assert := assert.New(t)
+
+ //DecodeFromBytes
+ buf := make([]byte, INTERFACE_NAMSIZ+49)
+ pos := INTERFACE_NAMSIZ
+ binary.BigEndian.PutUint32(buf[pos:], 1)
+ pos += 4
+ buf[pos] = INTERFACE_ACTIVE
+ pos += 1
+ binary.BigEndian.PutUint64(buf[pos:], 1)
+ pos += 8 // flags
+ binary.BigEndian.PutUint32(buf[pos:], 1)
+ pos += 4 // metric
+ binary.BigEndian.PutUint32(buf[pos:], 1500)
+ pos += 4 // MTU
+ binary.BigEndian.PutUint32(buf[pos:], 1500)
+ pos += 4 // MTU6
+ binary.BigEndian.PutUint32(buf[pos:], 200)
+ pos += 4 // bandwidth
+ binary.BigEndian.PutUint32(buf[pos:], 6)
+ pos += 4 // hwaddr_len
+ mac, _ := net.ParseMAC("01:23:45:67:89:ab")
+ copy(buf[pos:pos+6], []byte(mac))
+ pos += 4
+ b := &InterfaceUpdateBody{}
+ err := b.DecodeFromBytes(buf)
+ assert.Equal(nil, err)
+ assert.Equal("01:23:45:67:89:ab", b.HardwareAddr.String())
+
+ buf = make([]byte, INTERFACE_NAMSIZ+28)
+ b = &InterfaceUpdateBody{}
+ err = b.DecodeFromBytes(buf)
+ assert.NotEqual(nil, err)
+}
+
+func Test_InterfaceAddressUpdateBody(t *testing.T) {
+ assert := assert.New(t)
+
+ //DecodeFromBytes
+ buf := make([]byte, 11)
+ pos := 0
+ binary.BigEndian.PutUint32(buf[pos:], 0)
+ pos += 4
+ buf[pos] = 0x01
+ pos += 1
+ buf[pos] = 0x2
+ pos += 1
+ ip := net.ParseIP("192.168.100.1").To4()
+ copy(buf[pos:pos+4], []byte(ip))
+ pos += 4
+ buf[pos] = byte(24)
+
+ b := &InterfaceAddressUpdateBody{}
+ err := b.DecodeFromBytes(buf)
+ assert.Equal(uint32(0), b.Index)
+ assert.Equal(uint8(1), b.Flags)
+ assert.Equal("192.168.100.1", b.Prefix.String())
+ assert.Equal(uint8(24), b.Length)
+
+ // af invalid
+ buf[5] = 0x4
+ pos += 1
+ b = &InterfaceAddressUpdateBody{}
+ err = b.DecodeFromBytes(buf)
+ assert.NotEqual(nil, err)
+}
+
+func Test_RouterIDUpdateBody(t *testing.T) {
+ assert := assert.New(t)
+
+ //DecodeFromBytes
+ buf := make([]byte, 6)
+ pos := 0
+ buf[pos] = 0x2
+ pos += 1
+ ip := net.ParseIP("192.168.100.1").To4()
+ copy(buf[pos:pos+4], []byte(ip))
+ pos += 4
+ buf[pos] = byte(32)
+
+ b := &RouterIDUpdateBody{}
+ err := b.DecodeFromBytes(buf)
+ assert.Equal(nil, err)
+ assert.Equal("192.168.100.1", b.Prefix.String())
+ assert.Equal(uint8(32), b.Length)
+
+ // af invalid
+ buf[0] = 0x4
+ pos += 1
+ b = &RouterIDUpdateBody{}
+ err = b.DecodeFromBytes(buf)
+ assert.NotEqual(nil, err)
+}
+
+func Test_IPRouteBody_IPv4(t *testing.T) {
+ assert := assert.New(t)
+
+ //DecodeFromBytes IPV4_ROUTE
+ buf := make([]byte, 22)
+ buf[0] = byte(ROUTE_CONNECT)
+ buf[1] = byte(FLAG_SELECTED)
+ buf[2] = MESSAGE_NEXTHOP | MESSAGE_DISTANCE | MESSAGE_METRIC
+ buf[3] = 24
+ ip := net.ParseIP("192.168.100.0").To4()
+ copy(buf[4:7], []byte(ip))
+
+ buf[7] = 1
+ nexthop := net.ParseIP("0.0.0.0").To4()
+ copy(buf[8:12], []byte(nexthop))
+
+ buf[12] = 1
+ binary.BigEndian.PutUint32(buf[13:], 1)
+ buf[17] = 0 // distance
+ binary.BigEndian.PutUint32(buf[18:], 1)
+ r := &IPRouteBody{Api: IPV4_ROUTE_ADD}
+ err := r.DecodeFromBytes(buf)
+
+ assert.Equal(nil, err)
+ assert.Equal("192.168.100.0", r.Prefix.String())
+ assert.Equal(uint8(0x18), r.PrefixLength)
+ assert.Equal(uint8(MESSAGE_NEXTHOP|MESSAGE_DISTANCE|MESSAGE_METRIC), r.Message)
+ assert.Equal("0.0.0.0", r.Nexthops[0].String())
+ assert.Equal(uint32(1), r.Ifindexs[0])
+ assert.Equal(uint8(0), r.Distance)
+ assert.Equal(uint32(1), r.Metric)
+
+ //Serialize
+ buf, err = r.Serialize()
+ assert.Equal(nil, err)
+ assert.Equal([]byte{0x2, 0x10, 0xd}, buf[0:3])
+ assert.Equal([]byte{0x0, 0x1}, buf[3:5])
+ assert.Equal(byte(24), buf[5])
+ ip = net.ParseIP("192.168.100.0").To4()
+ assert.Equal([]byte(ip)[0:3], buf[6:9])
+ assert.Equal(byte(NEXTHOP_IPV4), buf[10])
+ assert.Equal(byte(NEXTHOP_IFINDEX), buf[15])
+ assert.Equal(byte(0x0), buf[20])
+
+ bi := make([]byte, 4)
+ binary.BigEndian.PutUint32(bi, 1)
+ assert.Equal(bi, buf[21:])
+
+ // length invalid
+ buf = make([]byte, 18)
+ buf[0] = byte(ROUTE_CONNECT)
+ buf[1] = byte(FLAG_SELECTED)
+ buf[2] = MESSAGE_NEXTHOP | MESSAGE_DISTANCE | MESSAGE_METRIC
+ buf[3] = 24
+ ip = net.ParseIP("192.168.100.0").To4()
+ copy(buf[4:7], []byte(ip))
+ buf[7] = 1
+ nexthop = net.ParseIP("0.0.0.0").To4()
+ copy(buf[8:12], []byte(nexthop))
+ buf[12] = 1
+ binary.BigEndian.PutUint32(buf[13:], 1)
+
+ r = &IPRouteBody{Api: IPV4_ROUTE_ADD}
+ err = r.DecodeFromBytes(buf)
+ assert.Equal("message length invalid", err.Error())
+
+ // no nexthop
+ buf = make([]byte, 12)
+ buf[0] = byte(ROUTE_CONNECT)
+ buf[1] = byte(FLAG_SELECTED)
+ buf[2] = MESSAGE_DISTANCE | MESSAGE_METRIC
+ buf[3] = 24
+ ip = net.ParseIP("192.168.100.0").To4()
+ copy(buf[4:7], []byte(ip))
+ buf[7] = 1
+ binary.BigEndian.PutUint32(buf[8:], 0)
+ r = &IPRouteBody{Api: IPV6_ROUTE_ADD}
+ err = r.DecodeFromBytes(buf)
+ assert.Equal(nil, err)
+
+}
+
+func Test_IPRouteBody_IPv6(t *testing.T) {
+ assert := assert.New(t)
+
+ //DecodeFromBytes IPV6_ROUTE
+ buf := make([]byte, 39)
+ buf[0] = byte(ROUTE_CONNECT)
+ buf[1] = byte(FLAG_SELECTED)
+ buf[2] = MESSAGE_NEXTHOP | MESSAGE_DISTANCE | MESSAGE_METRIC
+ buf[3] = 64
+ ip := net.ParseIP("2001:db8:0:f101::").To16()
+ copy(buf[4:12], []byte(ip))
+
+ buf[12] = 1
+ nexthop := net.ParseIP("::").To16()
+ copy(buf[13:29], []byte(nexthop))
+ // ifindex
+ buf[29] = 1
+ binary.BigEndian.PutUint32(buf[30:], 1)
+
+ buf[34] = 0 // distance
+ binary.BigEndian.PutUint32(buf[35:], 1)
+ r := &IPRouteBody{Api: IPV6_ROUTE_ADD}
+ err := r.DecodeFromBytes(buf)
+
+ assert.Equal(nil, err)
+ assert.Equal("2001:db8:0:f101::", r.Prefix.String())
+ assert.Equal(uint8(64), r.PrefixLength)
+ assert.Equal(uint8(MESSAGE_NEXTHOP|MESSAGE_DISTANCE|MESSAGE_METRIC), r.Message)
+ assert.Equal("::", r.Nexthops[0].String())
+ assert.Equal(uint32(1), r.Ifindexs[0])
+ assert.Equal(uint8(0), r.Distance)
+ assert.Equal(uint32(1), r.Metric)
+
+ //Serialize
+ buf, err = r.Serialize()
+ assert.Equal(nil, err)
+ assert.Equal([]byte{0x2, 0x10, 0xd}, buf[0:3])
+ assert.Equal([]byte{0x0, 0x1}, buf[3:5])
+ assert.Equal(byte(64), buf[5])
+ ip = net.ParseIP("2001:db8:0:f101::").To16()
+ assert.Equal([]byte(ip)[0:8], buf[6:14])
+ assert.Equal(byte(2), buf[14])
+ assert.Equal(byte(NEXTHOP_IPV6), buf[15])
+ ip = net.ParseIP("::").To16()
+ assert.Equal([]byte(ip), buf[16:32])
+ assert.Equal(byte(NEXTHOP_IFINDEX), buf[32])
+ bi := make([]byte, 4)
+ binary.BigEndian.PutUint32(bi, 1)
+ assert.Equal(bi, buf[33:37])
+
+ //distance
+ assert.Equal(byte(0), buf[37])
+ bi = make([]byte, 4)
+ binary.BigEndian.PutUint32(bi, 1)
+ assert.Equal(bi, buf[38:])
+
+ // length invalid
+ buf = make([]byte, 50)
+ buf[0] = byte(ROUTE_CONNECT)
+ buf[1] = byte(FLAG_SELECTED)
+ buf[2] = MESSAGE_NEXTHOP | MESSAGE_DISTANCE | MESSAGE_METRIC
+ buf[3] = 24
+ ip = net.ParseIP("2001:db8:0:f101::").To4()
+ copy(buf[4:12], []byte(ip))
+ buf[13] = 1
+ nexthop = net.ParseIP("::").To16()
+ copy(buf[14:30], []byte(nexthop))
+ buf[31] = 1
+ binary.BigEndian.PutUint32(buf[32:], 1)
+
+ r = &IPRouteBody{Api: IPV6_ROUTE_ADD}
+ err = r.DecodeFromBytes(buf)
+ assert.Equal("message length invalid", err.Error())
+
+ // no nexthop
+ buf = make([]byte, 11)
+ buf[0] = byte(ROUTE_CONNECT)
+ buf[1] = byte(FLAG_SELECTED)
+ buf[2] = MESSAGE_DISTANCE | MESSAGE_METRIC
+ buf[3] = 16
+ ip = net.ParseIP("2501::").To16()
+ copy(buf[4:6], []byte(ip))
+ buf[6] = 1
+ binary.BigEndian.PutUint32(buf[7:], 0)
+ r = &IPRouteBody{Api: IPV6_ROUTE_ADD}
+ err = r.DecodeFromBytes(buf)
+ assert.Equal(nil, err)
+}