mirror of
https://github.com/osrg/gobgp.git
synced 2024-05-11 05:55:10 +00:00
zebra: merge gozebra
Seems that no good reason to have a separate repo for gozebra. Signed-off-by: FUJITA Tomonori <[email protected]>
This commit is contained in:
+1
-1
@@ -25,7 +25,7 @@ import (
|
||||
"github.com/osrg/gobgp/packet"
|
||||
"github.com/osrg/gobgp/policy"
|
||||
"github.com/osrg/gobgp/table"
|
||||
zebra "github.com/osrg/gozebra"
|
||||
"github.com/osrg/gobgp/zebra"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ package server
|
||||
import (
|
||||
"github.com/osrg/gobgp/packet"
|
||||
"github.com/osrg/gobgp/table"
|
||||
zebra "github.com/osrg/gozebra"
|
||||
"github.com/osrg/gobgp/zebra"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
// generated by stringer --type SAFI,API_TYPE,ROUTE_TYPE,NEXTHOP_FLAG; DO NOT EDIT
|
||||
|
||||
package zebra
|
||||
|
||||
import "fmt"
|
||||
|
||||
const _SAFI_name = "SAFI_UNICASTSAFI_MULTICASTSAFI_RESERVED_3SAFI_MPLS_VPNSAFI_MAX"
|
||||
|
||||
var _SAFI_index = [...]uint8{0, 12, 26, 41, 54, 62}
|
||||
|
||||
func (i SAFI) String() string {
|
||||
i -= 1
|
||||
if i+1 >= SAFI(len(_SAFI_index)) {
|
||||
return fmt.Sprintf("SAFI(%d)", i+1)
|
||||
}
|
||||
return _SAFI_name[_SAFI_index[i]:_SAFI_index[i+1]]
|
||||
}
|
||||
|
||||
const _API_TYPE_name = "INTERFACE_ADDINTERFACE_DELETEINTERFACE_ADDRESS_ADDINTERFACE_ADDRESS_DELETEINTERFACE_UPINTERFACE_DOWNIPV4_ROUTE_ADDIPV4_ROUTE_DELETEIPV6_ROUTE_ADDIPV6_ROUTE_DELETEREDISTRIBUTE_ADDREDISTRIBUTE_DELETEREDISTRIBUTE_DEFAULT_ADDREDISTRIBUTE_DEFAULT_DELETEIPV4_NEXTHOP_LOOKUPIPV6_NEXTHOP_LOOKUPIPV4_IMPORT_LOOKUPIPV6_IMPORT_LOOKUPINTERFACE_RENAMEROUTER_ID_ADDROUTER_ID_DELETEROUTER_ID_UPDATEHELLOMESSAGE_MAX"
|
||||
|
||||
var _API_TYPE_index = [...]uint16{0, 13, 29, 50, 74, 86, 100, 114, 131, 145, 162, 178, 197, 221, 248, 267, 286, 304, 322, 338, 351, 367, 383, 388, 399}
|
||||
|
||||
func (i API_TYPE) String() string {
|
||||
i -= 1
|
||||
if i+1 >= API_TYPE(len(_API_TYPE_index)) {
|
||||
return fmt.Sprintf("API_TYPE(%d)", i+1)
|
||||
}
|
||||
return _API_TYPE_name[_API_TYPE_index[i]:_API_TYPE_index[i+1]]
|
||||
}
|
||||
|
||||
const _ROUTE_TYPE_name = "ROUTE_SYSTEMROUTE_KERNELROUTE_CONNECTROUTE_STATICROUTE_RIPROUTE_RIPNGROUTE_OSPFROUTE_OSPF6ROUTE_ISISROUTE_BGPROUTE_HSLSROUTE_OLSRROUTE_BABELROUTE_MAX"
|
||||
|
||||
var _ROUTE_TYPE_index = [...]uint8{0, 12, 24, 37, 49, 58, 69, 79, 90, 100, 109, 119, 129, 140, 149}
|
||||
|
||||
func (i ROUTE_TYPE) String() string {
|
||||
if i+1 >= ROUTE_TYPE(len(_ROUTE_TYPE_index)) {
|
||||
return fmt.Sprintf("ROUTE_TYPE(%d)", i)
|
||||
}
|
||||
return _ROUTE_TYPE_name[_ROUTE_TYPE_index[i]:_ROUTE_TYPE_index[i+1]]
|
||||
}
|
||||
|
||||
const _NEXTHOP_FLAG_name = "NEXTHOP_IFINDEXNEXTHOP_IFNAMENEXTHOP_IPV4NEXTHOP_IPV4_IFINDEXNEXTHOP_IPV4_IFNAMENEXTHOP_IPV6NEXTHOP_IPV6_IFINDEXNEXTHOP_IPV6_IFNAMENEXTHOP_BLACKHOLE"
|
||||
|
||||
var _NEXTHOP_FLAG_index = [...]uint8{0, 15, 29, 41, 61, 80, 92, 112, 131, 148}
|
||||
|
||||
func (i NEXTHOP_FLAG) String() string {
|
||||
i -= 1
|
||||
if i+1 >= NEXTHOP_FLAG(len(_NEXTHOP_FLAG_index)) {
|
||||
return fmt.Sprintf("NEXTHOP_FLAG(%d)", i+1)
|
||||
}
|
||||
return _NEXTHOP_FLAG_name[_NEXTHOP_FLAG_index[i]:_NEXTHOP_FLAG_index[i+1]]
|
||||
}
|
||||
+641
@@ -0,0 +1,641 @@
|
||||
// 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"
|
||||
"fmt"
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const (
|
||||
HEADER_SIZE = 6
|
||||
HEADER_MARKER = 255
|
||||
VERSION = 2
|
||||
INTERFACE_NAMSIZ = 20
|
||||
)
|
||||
|
||||
type INTERFACE_STATUS uint8
|
||||
|
||||
const (
|
||||
INTERFACE_ACTIVE = 0x01
|
||||
INTERFACE_SUB = 0x02
|
||||
INTERFACE_LINKDETECTION = 0x04
|
||||
)
|
||||
|
||||
func (t INTERFACE_STATUS) String() string {
|
||||
ss := make([]string, 0, 3)
|
||||
if t&INTERFACE_ACTIVE > 0 {
|
||||
ss = append(ss, "ACTIVE")
|
||||
}
|
||||
if t&INTERFACE_SUB > 0 {
|
||||
ss = append(ss, "SUB")
|
||||
}
|
||||
if t&INTERFACE_LINKDETECTION > 0 {
|
||||
ss = append(ss, "LINKDETECTION")
|
||||
}
|
||||
return strings.Join(ss, "|")
|
||||
}
|
||||
|
||||
// Subsequent Address Family Identifier.
|
||||
type SAFI uint8
|
||||
|
||||
const (
|
||||
_ SAFI = iota
|
||||
SAFI_UNICAST
|
||||
SAFI_MULTICAST
|
||||
SAFI_RESERVED_3
|
||||
SAFI_MPLS_VPN
|
||||
SAFI_MAX
|
||||
)
|
||||
|
||||
// API Types.
|
||||
type API_TYPE uint16
|
||||
|
||||
const (
|
||||
_ API_TYPE = iota
|
||||
INTERFACE_ADD
|
||||
INTERFACE_DELETE
|
||||
INTERFACE_ADDRESS_ADD
|
||||
INTERFACE_ADDRESS_DELETE
|
||||
INTERFACE_UP
|
||||
INTERFACE_DOWN
|
||||
IPV4_ROUTE_ADD
|
||||
IPV4_ROUTE_DELETE
|
||||
IPV6_ROUTE_ADD
|
||||
IPV6_ROUTE_DELETE
|
||||
REDISTRIBUTE_ADD
|
||||
REDISTRIBUTE_DELETE
|
||||
REDISTRIBUTE_DEFAULT_ADD
|
||||
REDISTRIBUTE_DEFAULT_DELETE
|
||||
IPV4_NEXTHOP_LOOKUP
|
||||
IPV6_NEXTHOP_LOOKUP
|
||||
IPV4_IMPORT_LOOKUP
|
||||
IPV6_IMPORT_LOOKUP
|
||||
INTERFACE_RENAME
|
||||
ROUTER_ID_ADD
|
||||
ROUTER_ID_DELETE
|
||||
ROUTER_ID_UPDATE
|
||||
HELLO
|
||||
MESSAGE_MAX
|
||||
)
|
||||
|
||||
// Route Types.
|
||||
type ROUTE_TYPE uint8
|
||||
|
||||
const (
|
||||
ROUTE_SYSTEM ROUTE_TYPE = iota
|
||||
ROUTE_KERNEL
|
||||
ROUTE_CONNECT
|
||||
ROUTE_STATIC
|
||||
ROUTE_RIP
|
||||
ROUTE_RIPNG
|
||||
ROUTE_OSPF
|
||||
ROUTE_OSPF6
|
||||
ROUTE_ISIS
|
||||
ROUTE_BGP
|
||||
ROUTE_HSLS
|
||||
ROUTE_OLSR
|
||||
ROUTE_BABEL
|
||||
ROUTE_MAX
|
||||
)
|
||||
|
||||
const (
|
||||
MESSAGE_NEXTHOP = 0x01
|
||||
MESSAGE_IFINDEX = 0x02
|
||||
MESSAGE_DISTANCE = 0x04
|
||||
MESSAGE_METRIC = 0x08
|
||||
)
|
||||
|
||||
// Message Flags
|
||||
type FLAG uint64
|
||||
|
||||
const (
|
||||
FLAG_INTERNAL FLAG = 0x01
|
||||
FLAG_SELFROUTE FLAG = 0x02
|
||||
FLAG_BLACKHOLE FLAG = 0x04
|
||||
FLAG_IBGP FLAG = 0x08
|
||||
FLAG_SELECTED FLAG = 0x10
|
||||
FLAG_CHANGED FLAG = 0x20
|
||||
FLAG_STATIC FLAG = 0x40
|
||||
FLAG_REJECT FLAG = 0x80
|
||||
)
|
||||
|
||||
func (t FLAG) String() string {
|
||||
var ss []string
|
||||
if t&FLAG_INTERNAL > 0 {
|
||||
ss = append(ss, "FLAG_INTERNAL")
|
||||
}
|
||||
if t&FLAG_SELFROUTE > 0 {
|
||||
ss = append(ss, "FLAG_SELFROUTE")
|
||||
}
|
||||
if t&FLAG_BLACKHOLE > 0 {
|
||||
ss = append(ss, "FLAG_BLACKHOLE")
|
||||
}
|
||||
if t&FLAG_IBGP > 0 {
|
||||
ss = append(ss, "FLAG_IBGP")
|
||||
}
|
||||
if t&FLAG_SELECTED > 0 {
|
||||
ss = append(ss, "FLAG_SELECTED")
|
||||
}
|
||||
if t&FLAG_CHANGED > 0 {
|
||||
ss = append(ss, "FLAG_CHANGED")
|
||||
}
|
||||
if t&FLAG_STATIC > 0 {
|
||||
ss = append(ss, "FLAG_STATIC")
|
||||
}
|
||||
if t&FLAG_REJECT > 0 {
|
||||
ss = append(ss, "FLAG_REJECT")
|
||||
}
|
||||
return strings.Join(ss, "|")
|
||||
}
|
||||
|
||||
// Nexthop Flags.
|
||||
type NEXTHOP_FLAG uint8
|
||||
|
||||
const (
|
||||
_ NEXTHOP_FLAG = iota
|
||||
NEXTHOP_IFINDEX
|
||||
NEXTHOP_IFNAME
|
||||
NEXTHOP_IPV4
|
||||
NEXTHOP_IPV4_IFINDEX
|
||||
NEXTHOP_IPV4_IFNAME
|
||||
NEXTHOP_IPV6
|
||||
NEXTHOP_IPV6_IFINDEX
|
||||
NEXTHOP_IPV6_IFNAME
|
||||
NEXTHOP_BLACKHOLE
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
outgoing chan *Message
|
||||
incoming chan *Message
|
||||
redistDefault ROUTE_TYPE
|
||||
conn net.Conn
|
||||
}
|
||||
|
||||
func NewClient(network, address string, typ ROUTE_TYPE) (*Client, error) {
|
||||
conn, err := net.Dial(network, address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outgoing := make(chan *Message)
|
||||
go func() {
|
||||
for {
|
||||
m, more := <-outgoing
|
||||
if more {
|
||||
b, err := m.Serialize()
|
||||
if err != nil {
|
||||
log.Warnf("failed to serialize: %s", m)
|
||||
continue
|
||||
}
|
||||
|
||||
_, err = conn.Write(b)
|
||||
if err != nil {
|
||||
log.Errorf("failed to write: ", err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
log.Debug("finish outgoing loop")
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
incoming := make(chan *Message, 64)
|
||||
go func() error {
|
||||
for {
|
||||
headerBuf, err := readAll(conn, HEADER_SIZE)
|
||||
if err != nil {
|
||||
log.Error("failed to read header: ", err)
|
||||
return err
|
||||
}
|
||||
|
||||
hd := &Header{}
|
||||
err = hd.DecodeFromBytes(headerBuf)
|
||||
if err != nil {
|
||||
log.Error("failed to decode header: ", err)
|
||||
return err
|
||||
}
|
||||
|
||||
bodyBuf, err := readAll(conn, int(hd.Len-HEADER_SIZE))
|
||||
if err != nil {
|
||||
log.Error("failed to read body: ", err)
|
||||
return err
|
||||
}
|
||||
|
||||
m, err := ParseMessage(hd, bodyBuf)
|
||||
if err != nil {
|
||||
log.Warn("failed to parse message: ", err)
|
||||
continue
|
||||
}
|
||||
|
||||
incoming <- m
|
||||
}
|
||||
}()
|
||||
return &Client{
|
||||
outgoing: outgoing,
|
||||
incoming: incoming,
|
||||
redistDefault: typ,
|
||||
conn: conn,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func readAll(conn net.Conn, length int) ([]byte, error) {
|
||||
buf := make([]byte, length)
|
||||
_, err := io.ReadFull(conn, buf)
|
||||
return buf, err
|
||||
}
|
||||
|
||||
func (c *Client) Recieve() chan *Message {
|
||||
return c.incoming
|
||||
}
|
||||
|
||||
func (c *Client) Send(m *Message) {
|
||||
c.outgoing <- m
|
||||
}
|
||||
|
||||
func (c *Client) SendCommand(command API_TYPE, body Body) error {
|
||||
m := &Message{
|
||||
Header: Header{
|
||||
Len: HEADER_SIZE,
|
||||
Marker: HEADER_MARKER,
|
||||
Version: VERSION,
|
||||
Command: command,
|
||||
},
|
||||
Body: body,
|
||||
}
|
||||
c.Send(m)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) SendHello() error {
|
||||
if c.redistDefault > 0 {
|
||||
body := &HelloBody{
|
||||
Redist: c.redistDefault,
|
||||
}
|
||||
return c.SendCommand(HELLO, body)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) SendRouterIDAdd() error {
|
||||
return c.SendCommand(ROUTER_ID_ADD, nil)
|
||||
}
|
||||
|
||||
func (c *Client) SendInterfaceAdd() error {
|
||||
return c.SendCommand(INTERFACE_ADD, nil)
|
||||
}
|
||||
|
||||
func (c *Client) Close() error {
|
||||
close(c.outgoing)
|
||||
return c.conn.Close()
|
||||
}
|
||||
|
||||
type Header struct {
|
||||
Len uint16
|
||||
Marker uint8
|
||||
Version uint8
|
||||
Command API_TYPE
|
||||
}
|
||||
|
||||
func (h *Header) Serialize() ([]byte, error) {
|
||||
buf := make([]byte, HEADER_SIZE)
|
||||
binary.BigEndian.PutUint16(buf[0:], h.Len)
|
||||
buf[2] = h.Marker
|
||||
buf[3] = h.Version
|
||||
binary.BigEndian.PutUint16(buf[4:], uint16(h.Command))
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
func (h *Header) DecodeFromBytes(data []byte) error {
|
||||
if uint16(len(data)) < HEADER_SIZE {
|
||||
return fmt.Errorf("Not all ZAPI message header")
|
||||
}
|
||||
h.Len = binary.BigEndian.Uint16(data[0:2])
|
||||
h.Marker = data[2]
|
||||
h.Version = data[3]
|
||||
h.Command = API_TYPE(binary.BigEndian.Uint16(data[4:6]))
|
||||
return nil
|
||||
}
|
||||
|
||||
type Body interface {
|
||||
DecodeFromBytes([]byte) error
|
||||
Serialize() ([]byte, error)
|
||||
}
|
||||
|
||||
type HelloBody struct {
|
||||
Redist ROUTE_TYPE
|
||||
}
|
||||
|
||||
func (b *HelloBody) DecodeFromBytes(data []byte) error {
|
||||
b.Redist = ROUTE_TYPE(data[0])
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *HelloBody) Serialize() ([]byte, error) {
|
||||
return []byte{uint8(b.Redist)}, nil
|
||||
}
|
||||
|
||||
type InterfaceUpdateBody struct {
|
||||
Name string
|
||||
Index uint32
|
||||
Status INTERFACE_STATUS
|
||||
Flags uint64
|
||||
Metric uint32
|
||||
MTU uint32
|
||||
MTU6 uint32
|
||||
Bandwidth uint32
|
||||
HardwareAddr net.HardwareAddr
|
||||
}
|
||||
|
||||
func (b *InterfaceUpdateBody) DecodeFromBytes(data []byte) error {
|
||||
if len(data) < INTERFACE_NAMSIZ+29 {
|
||||
return fmt.Errorf("lack of bytes. need %d but %d", INTERFACE_NAMSIZ+29, len(data))
|
||||
}
|
||||
|
||||
b.Name = string(data[:INTERFACE_NAMSIZ])
|
||||
data = data[INTERFACE_NAMSIZ:]
|
||||
b.Index = binary.BigEndian.Uint32(data[:4])
|
||||
b.Status = INTERFACE_STATUS(data[4])
|
||||
b.Flags = binary.BigEndian.Uint64(data[5:13])
|
||||
b.Metric = binary.BigEndian.Uint32(data[13:17])
|
||||
b.MTU = binary.BigEndian.Uint32(data[17:21])
|
||||
b.MTU6 = binary.BigEndian.Uint32(data[21:25])
|
||||
b.Bandwidth = binary.BigEndian.Uint32(data[25:29])
|
||||
l := binary.BigEndian.Uint32(data[29:33])
|
||||
if l > 0 {
|
||||
b.HardwareAddr = data[33 : 33+l]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *InterfaceUpdateBody) Serialize() ([]byte, error) {
|
||||
return []byte{}, nil
|
||||
}
|
||||
func intfflag2string(flag uint64) string {
|
||||
ss := make([]string, 0, 10)
|
||||
if flag&syscall.IFF_UP > 0 {
|
||||
ss = append(ss, "UP")
|
||||
}
|
||||
if flag&syscall.IFF_BROADCAST > 0 {
|
||||
ss = append(ss, "BROADCAST")
|
||||
}
|
||||
if flag&syscall.IFF_DEBUG > 0 {
|
||||
ss = append(ss, "DEBUG")
|
||||
}
|
||||
if flag&syscall.IFF_LOOPBACK > 0 {
|
||||
ss = append(ss, "LOOPBACK")
|
||||
}
|
||||
if flag&syscall.IFF_POINTOPOINT > 0 {
|
||||
ss = append(ss, "POINTOPOINT")
|
||||
}
|
||||
if flag&syscall.IFF_NOTRAILERS > 0 {
|
||||
ss = append(ss, "NOTRAILERS")
|
||||
}
|
||||
if flag&syscall.IFF_RUNNING > 0 {
|
||||
ss = append(ss, "RUNNING")
|
||||
}
|
||||
if flag&syscall.IFF_NOARP > 0 {
|
||||
ss = append(ss, "NOARP")
|
||||
}
|
||||
if flag&syscall.IFF_PROMISC > 0 {
|
||||
ss = append(ss, "PROMISC")
|
||||
}
|
||||
if flag&syscall.IFF_ALLMULTI > 0 {
|
||||
ss = append(ss, "ALLMULTI")
|
||||
}
|
||||
if flag&syscall.IFF_MASTER > 0 {
|
||||
ss = append(ss, "MASTER")
|
||||
}
|
||||
if flag&syscall.IFF_SLAVE > 0 {
|
||||
ss = append(ss, "SLAVE")
|
||||
}
|
||||
if flag&syscall.IFF_MULTICAST > 0 {
|
||||
ss = append(ss, "MULTICAST")
|
||||
}
|
||||
if flag&syscall.IFF_PORTSEL > 0 {
|
||||
ss = append(ss, "PORTSEL")
|
||||
}
|
||||
if flag&syscall.IFF_AUTOMEDIA > 0 {
|
||||
ss = append(ss, "AUTOMEDIA")
|
||||
}
|
||||
if flag&syscall.IFF_DYNAMIC > 0 {
|
||||
ss = append(ss, "DYNAMIC")
|
||||
}
|
||||
// if flag&syscall.IFF_LOWER_UP > 0 {
|
||||
// ss = append(ss, "LOWER_UP")
|
||||
// }
|
||||
// if flag&syscall.IFF_DORMANT > 0 {
|
||||
// ss = append(ss, "DORMANT")
|
||||
// }
|
||||
// if flag&syscall.IFF_ECHO > 0 {
|
||||
// ss = append(ss, "ECHO")
|
||||
// }
|
||||
return strings.Join(ss, " | ")
|
||||
}
|
||||
|
||||
func (b *InterfaceUpdateBody) String() string {
|
||||
s := fmt.Sprintf("name: %s, idx: %d, status: %s, flags: %s, metric: %d, mtu: %d, mtu6: %d, bandwith: %d", b.Name, b.Index, b.Status, intfflag2string(b.Flags), b.Metric, b.MTU, b.MTU6, b.Bandwidth)
|
||||
if len(b.HardwareAddr) > 0 {
|
||||
return s + fmt.Sprintf(", mac: %s", b.HardwareAddr)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
type InterfaceAddressUpdateBody struct {
|
||||
Index uint32
|
||||
Flags uint8
|
||||
Prefix net.IP
|
||||
Length uint8
|
||||
}
|
||||
|
||||
func (b *InterfaceAddressUpdateBody) DecodeFromBytes(data []byte) error {
|
||||
b.Index = binary.BigEndian.Uint32(data[:4])
|
||||
b.Flags = data[4]
|
||||
family := data[5]
|
||||
var addrlen int8
|
||||
switch family {
|
||||
case syscall.AF_INET:
|
||||
addrlen = net.IPv4len
|
||||
case syscall.AF_INET6:
|
||||
addrlen = net.IPv6len
|
||||
default:
|
||||
return fmt.Errorf("unknown address family: %d", family)
|
||||
}
|
||||
b.Prefix = data[6 : 6+addrlen]
|
||||
b.Length = data[6+addrlen]
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *InterfaceAddressUpdateBody) Serialize() ([]byte, error) {
|
||||
return []byte{}, nil
|
||||
}
|
||||
|
||||
func (b *InterfaceAddressUpdateBody) String() string {
|
||||
return fmt.Sprintf("idx: %d, flags: %d, addr: %s/%d", b.Index, b.Flags, b.Prefix, b.Length)
|
||||
}
|
||||
|
||||
type RouterIDUpdateBody struct {
|
||||
Length uint8
|
||||
Prefix net.IP
|
||||
}
|
||||
|
||||
func (b *RouterIDUpdateBody) DecodeFromBytes(data []byte) error {
|
||||
family := data[0]
|
||||
var addrlen int8
|
||||
switch family {
|
||||
case syscall.AF_INET:
|
||||
addrlen = net.IPv4len
|
||||
case syscall.AF_INET6:
|
||||
addrlen = net.IPv6len
|
||||
default:
|
||||
return fmt.Errorf("unknown address family: %d", family)
|
||||
}
|
||||
b.Prefix = data[1 : 1+addrlen]
|
||||
b.Length = data[1+addrlen]
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *RouterIDUpdateBody) Serialize() ([]byte, error) {
|
||||
return []byte{}, nil
|
||||
}
|
||||
|
||||
func (b *RouterIDUpdateBody) String() string {
|
||||
return fmt.Sprintf("id: %s/%d", b.Prefix, b.Length)
|
||||
}
|
||||
|
||||
type IPRouteBody struct {
|
||||
Type ROUTE_TYPE
|
||||
Flags FLAG
|
||||
Message uint8
|
||||
SAFI SAFI
|
||||
Prefix net.IP
|
||||
PrefixLength uint8
|
||||
Nexthops []net.IP
|
||||
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
|
||||
}
|
||||
|
||||
func (b *IPRouteBody) Serialize() ([]byte, error) {
|
||||
buf := make([]byte, 5)
|
||||
buf[0] = uint8(b.Type)
|
||||
buf[1] = uint8(b.Flags)
|
||||
buf[2] = b.Message
|
||||
binary.BigEndian.PutUint16(buf[3:], uint16(b.SAFI))
|
||||
bitlen := b.PrefixLength
|
||||
bytelen := (int(b.PrefixLength) + 7) / 8
|
||||
bbuf := make([]byte, bytelen)
|
||||
copy(bbuf, b.Prefix)
|
||||
if bitlen%8 != 0 {
|
||||
mask := 0xff00 >> (bitlen % 8)
|
||||
last_byte_value := bbuf[bytelen-1] & byte(mask)
|
||||
bbuf[bytelen-1] = last_byte_value
|
||||
}
|
||||
buf = append(buf, bitlen)
|
||||
buf = append(buf, bbuf...)
|
||||
|
||||
if b.Message&MESSAGE_NEXTHOP > 0 {
|
||||
if b.Flags&FLAG_BLACKHOLE > 0 {
|
||||
buf = append(buf, []byte{1, uint8(NEXTHOP_BLACKHOLE)}...)
|
||||
} else {
|
||||
buf = append(buf, uint8(len(b.Nexthops)+len(b.Ifindexs)))
|
||||
}
|
||||
|
||||
for _, v := range b.Nexthops {
|
||||
if v.To4() != nil {
|
||||
buf = append(buf, uint8(NEXTHOP_IPV4))
|
||||
buf = append(buf, v.To4()...)
|
||||
} else {
|
||||
buf = append(buf, uint8(NEXTHOP_IPV6))
|
||||
buf = append(buf, v.To16()...)
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range b.Ifindexs {
|
||||
buf = append(buf, uint8(NEXTHOP_IFINDEX))
|
||||
bbuf := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(bbuf, v)
|
||||
buf = append(buf, bbuf...)
|
||||
}
|
||||
}
|
||||
|
||||
if b.Message&MESSAGE_DISTANCE > 0 {
|
||||
buf = append(buf, b.Distance)
|
||||
}
|
||||
if b.Message&MESSAGE_METRIC > 0 {
|
||||
bbuf := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(bbuf, b.Metric)
|
||||
buf = append(buf, bbuf...)
|
||||
}
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
type Message struct {
|
||||
Header Header
|
||||
Body Body
|
||||
}
|
||||
|
||||
func (m *Message) Serialize() ([]byte, error) {
|
||||
var body []byte
|
||||
if m.Body != nil {
|
||||
var err error
|
||||
body, err = m.Body.Serialize()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
m.Header.Len = uint16(len(body)) + HEADER_SIZE
|
||||
hdr, err := m.Header.Serialize()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append(hdr, body...), nil
|
||||
}
|
||||
|
||||
func ParseMessage(hdr *Header, data []byte) (*Message, error) {
|
||||
m := &Message{Header: *hdr}
|
||||
|
||||
switch m.Header.Command {
|
||||
case INTERFACE_ADD, INTERFACE_DELETE, INTERFACE_UP, INTERFACE_DOWN:
|
||||
m.Body = &InterfaceUpdateBody{}
|
||||
case INTERFACE_ADDRESS_ADD, INTERFACE_ADDRESS_DELETE:
|
||||
m.Body = &InterfaceAddressUpdateBody{}
|
||||
case ROUTER_ID_UPDATE:
|
||||
m.Body = &RouterIDUpdateBody{}
|
||||
default:
|
||||
return nil, fmt.Errorf("Unknown zapi command: %d", m.Header.Command)
|
||||
}
|
||||
err := m.Body.DecodeFromBytes(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
Reference in New Issue
Block a user