diff options
author | Hiroshi Yokoi <yokoi.hiroshi@po.ntts.co.jp> | 2015-08-26 18:11:38 +0900 |
---|---|---|
committer | Hiroshi Yokoi <yokoi.hiroshi@po.ntts.co.jp> | 2015-09-01 19:42:02 +0900 |
commit | cc51c48a4934bde8f5a5555632633c3c8486b797 (patch) | |
tree | 14998dac3531e6a609bb414d2816f7f7d2ba1d5f | |
parent | f8d437ec0ea65656ca4c6d81ec48fe0f7099c60e (diff) |
zebra: distribute routes from zebra
Signed-off-by: Hiroshi Yokoi <yokoi.hiroshi@po.ntts.co.jp>
-rw-r--r-- | server/server.go | 22 | ||||
-rw-r--r-- | server/zclient.go | 63 | ||||
-rw-r--r-- | server/zclient_test.go | 104 | ||||
-rw-r--r-- | table/destination.go | 2 | ||||
-rw-r--r-- | table/path.go | 1 | ||||
-rw-r--r-- | zebra/zapi.go | 149 | ||||
-rw-r--r-- | zebra/zapi_test.go | 320 |
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) +} |