mirror of
https://github.com/cloudnativelabs/kube-router.git
synced 2025-10-13 10:51:05 +02:00
1349 lines
30 KiB
Go
1349 lines
30 KiB
Go
// 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"
|
|
"io"
|
|
"net"
|
|
"strings"
|
|
"syscall"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
const (
|
|
HEADER_MARKER = 255
|
|
INTERFACE_NAMSIZ = 20
|
|
)
|
|
|
|
type INTERFACE_STATUS uint8
|
|
|
|
const (
|
|
INTERFACE_ACTIVE = 0x01
|
|
INTERFACE_SUB = 0x02
|
|
INTERFACE_LINKDETECTION = 0x04
|
|
)
|
|
|
|
type LINK_TYPE uint32
|
|
|
|
const (
|
|
LINK_TYPE_UNKNOWN LINK_TYPE = iota
|
|
LINK_TYPE_ETHER
|
|
LINK_TYPE_EETHER
|
|
LINK_TYPE_AX25
|
|
LINK_TYPE_PRONET
|
|
LINK_TYPE_IEEE802
|
|
LINK_TYPE_ARCNET
|
|
LINK_TYPE_APPLETLK
|
|
LINK_TYPE_DLCI
|
|
LINK_TYPE_ATM
|
|
LINK_TYPE_METRICOM
|
|
LINK_TYPE_IEEE1394
|
|
LINK_TYPE_EUI64
|
|
LINK_TYPE_INFINIBAND
|
|
LINK_TYPE_SLIP
|
|
LINK_TYPE_CSLIP
|
|
LINK_TYPE_SLIP6
|
|
LINK_TYPE_CSLIP6
|
|
LINK_TYPE_RSRVD
|
|
LINK_TYPE_ADAPT
|
|
LINK_TYPE_ROSE
|
|
LINK_TYPE_X25
|
|
LINK_TYPE_PPP
|
|
LINK_TYPE_CHDLC
|
|
LINK_TYPE_LAPB
|
|
LINK_TYPE_RAWHDLC
|
|
LINK_TYPE_IPIP
|
|
LINK_TYPE_IPIP6
|
|
LINK_TYPE_FRAD
|
|
LINK_TYPE_SKIP
|
|
LINK_TYPE_LOOPBACK
|
|
LINK_TYPE_LOCALTLK
|
|
LINK_TYPE_FDDI
|
|
LINK_TYPE_SIT
|
|
LINK_TYPE_IPDDP
|
|
LINK_TYPE_IPGRE
|
|
LINK_TYPE_IP6GRE
|
|
LINK_TYPE_PIMREG
|
|
LINK_TYPE_HIPPI
|
|
LINK_TYPE_ECONET
|
|
LINK_TYPE_IRDA
|
|
LINK_TYPE_FCPP
|
|
LINK_TYPE_FCAL
|
|
LINK_TYPE_FCPL
|
|
LINK_TYPE_FCFABRIC
|
|
LINK_TYPE_IEEE802_TR
|
|
LINK_TYPE_IEEE80211
|
|
LINK_TYPE_IEEE80211_RADIOTAP
|
|
LINK_TYPE_IEEE802154
|
|
LINK_TYPE_IEEE802154_PHY
|
|
)
|
|
|
|
const VRF_DEFAULT = 0
|
|
|
|
func HeaderSize(version uint8) uint16 {
|
|
switch version {
|
|
case 3:
|
|
return 8
|
|
default:
|
|
return 6
|
|
}
|
|
}
|
|
|
|
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
|
|
IPV4_NEXTHOP_LOOKUP_MRIB
|
|
VRF_UNREGISTER
|
|
INTERFACE_LINK_PARAMS
|
|
NEXTHOP_REGISTER
|
|
NEXTHOP_UNREGISTER
|
|
NEXTHOP_UPDATE
|
|
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
|
|
)
|
|
|
|
var routeTypeValueMap = map[string]ROUTE_TYPE{
|
|
"system": ROUTE_SYSTEM,
|
|
"kernel": ROUTE_KERNEL,
|
|
"connect": ROUTE_CONNECT,
|
|
"static": ROUTE_STATIC,
|
|
"rip": ROUTE_RIP,
|
|
"ripng": ROUTE_RIPNG,
|
|
"ospf": ROUTE_OSPF,
|
|
"ospf3": ROUTE_OSPF6,
|
|
"isis": ROUTE_ISIS,
|
|
"bgp": ROUTE_BGP,
|
|
"hsls": ROUTE_HSLS,
|
|
"olsr": ROUTE_OLSR,
|
|
"babel": ROUTE_BABEL,
|
|
}
|
|
|
|
func RouteTypeFromString(typ string) (ROUTE_TYPE, error) {
|
|
t, ok := routeTypeValueMap[typ]
|
|
if ok {
|
|
return t, nil
|
|
}
|
|
return t, fmt.Errorf("unknown route type: %s", typ)
|
|
}
|
|
|
|
const (
|
|
MESSAGE_NEXTHOP = 0x01
|
|
MESSAGE_IFINDEX = 0x02
|
|
MESSAGE_DISTANCE = 0x04
|
|
MESSAGE_METRIC = 0x08
|
|
MESSAGE_MTU = 0x10
|
|
)
|
|
|
|
// 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
|
|
Version uint8
|
|
}
|
|
|
|
func NewClient(network, address string, typ ROUTE_TYPE, version uint8) (*Client, error) {
|
|
conn, err := net.Dial(network, address)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
outgoing := make(chan *Message)
|
|
incoming := make(chan *Message, 64)
|
|
if version != 3 {
|
|
version = 2
|
|
}
|
|
|
|
c := &Client{
|
|
outgoing: outgoing,
|
|
incoming: incoming,
|
|
redistDefault: typ,
|
|
conn: conn,
|
|
Version: version,
|
|
}
|
|
|
|
go func() {
|
|
for {
|
|
m, more := <-outgoing
|
|
if more {
|
|
b, err := m.Serialize()
|
|
if err != nil {
|
|
log.WithFields(log.Fields{
|
|
"Topic": "Zebra",
|
|
}).Warnf("failed to serialize: %s", m)
|
|
continue
|
|
}
|
|
|
|
_, err = conn.Write(b)
|
|
if err != nil {
|
|
log.WithFields(log.Fields{
|
|
"Topic": "Zebra",
|
|
}).Errorf("failed to write: %s", err)
|
|
close(outgoing)
|
|
}
|
|
} else {
|
|
log.Debug("finish outgoing loop")
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
// Send HELLO/ROUTER_ID_ADD messages to negotiate the Zebra message version.
|
|
c.SendHello()
|
|
c.SendRouterIDAdd()
|
|
|
|
receiveSingleMsg := func() (*Message, error) {
|
|
headerBuf, err := readAll(conn, int(HeaderSize(version)))
|
|
if err != nil {
|
|
err = fmt.Errorf("failed to read header: %s", err)
|
|
log.WithFields(log.Fields{
|
|
"Topic": "Zebra",
|
|
}).Error(err)
|
|
return nil, err
|
|
}
|
|
log.WithFields(log.Fields{
|
|
"Topic": "Zebra",
|
|
}).Debugf("read header from zebra: %v", headerBuf)
|
|
hd := &Header{}
|
|
err = hd.DecodeFromBytes(headerBuf)
|
|
if err != nil {
|
|
err = fmt.Errorf("failed to decode header: %s", err)
|
|
log.WithFields(log.Fields{
|
|
"Topic": "Zebra",
|
|
}).Error(err)
|
|
return nil, err
|
|
}
|
|
|
|
bodyBuf, err := readAll(conn, int(hd.Len-HeaderSize(version)))
|
|
if err != nil {
|
|
err = fmt.Errorf("failed to read body: %s", err)
|
|
log.WithFields(log.Fields{
|
|
"Topic": "Zebra",
|
|
}).Error(err)
|
|
return nil, err
|
|
}
|
|
log.WithFields(log.Fields{
|
|
"Topic": "Zebra",
|
|
}).Debugf("read body from zebra: %v", bodyBuf)
|
|
m, err := ParseMessage(hd, bodyBuf)
|
|
if err != nil {
|
|
log.WithFields(log.Fields{
|
|
"Topic": "Zebra",
|
|
}).Warnf("failed to parse message: %s", err)
|
|
return nil, nil
|
|
}
|
|
|
|
return m, nil
|
|
}
|
|
|
|
// Try to receive the first message from Zebra.
|
|
if m, err := receiveSingleMsg(); err != nil {
|
|
c.Close()
|
|
// Return error explicitly in order to retry connection.
|
|
return nil, err
|
|
} else if m != nil {
|
|
incoming <- m
|
|
}
|
|
|
|
// Start receive loop only when the first message successfully received.
|
|
go func() {
|
|
for {
|
|
if m, err := receiveSingleMsg(); err != nil {
|
|
return
|
|
} else if m != nil {
|
|
incoming <- m
|
|
}
|
|
}
|
|
}()
|
|
|
|
return c, 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) Receive() chan *Message {
|
|
return c.incoming
|
|
}
|
|
|
|
func (c *Client) Send(m *Message) {
|
|
defer func() {
|
|
if err := recover(); err != nil {
|
|
log.WithFields(log.Fields{
|
|
"Topic": "Zebra",
|
|
}).Debugf("recovered: %s", err)
|
|
}
|
|
}()
|
|
log.WithFields(log.Fields{
|
|
"Topic": "Zebra",
|
|
"Header": m.Header,
|
|
"Body": m.Body,
|
|
}).Debug("send command to zebra")
|
|
c.outgoing <- m
|
|
}
|
|
|
|
func (c *Client) SendCommand(command API_TYPE, vrfId uint16, body Body) error {
|
|
m := &Message{
|
|
Header: Header{
|
|
Len: HeaderSize(c.Version),
|
|
Marker: HEADER_MARKER,
|
|
Version: c.Version,
|
|
VrfId: vrfId,
|
|
Command: command,
|
|
},
|
|
Body: body,
|
|
}
|
|
c.Send(m)
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) SendHello() error {
|
|
if c.redistDefault > 0 {
|
|
body := &HelloBody{
|
|
RedistDefault: c.redistDefault,
|
|
}
|
|
return c.SendCommand(HELLO, VRF_DEFAULT, body)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) SendRouterIDAdd() error {
|
|
return c.SendCommand(ROUTER_ID_ADD, VRF_DEFAULT, nil)
|
|
}
|
|
|
|
func (c *Client) SendInterfaceAdd() error {
|
|
return c.SendCommand(INTERFACE_ADD, VRF_DEFAULT, nil)
|
|
}
|
|
|
|
func (c *Client) SendRedistribute(t ROUTE_TYPE, vrfId uint16) error {
|
|
if c.redistDefault != t {
|
|
body := &RedistributeBody{
|
|
Redist: t,
|
|
}
|
|
if e := c.SendCommand(REDISTRIBUTE_ADD, vrfId, body); e != nil {
|
|
return e
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) SendRedistributeDelete(t ROUTE_TYPE) error {
|
|
|
|
if t < ROUTE_MAX {
|
|
body := &RedistributeBody{
|
|
Redist: t,
|
|
}
|
|
if e := c.SendCommand(REDISTRIBUTE_DELETE, VRF_DEFAULT, body); e != nil {
|
|
return e
|
|
}
|
|
} else {
|
|
return fmt.Errorf("unknown route type: %d", t)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) Close() error {
|
|
close(c.outgoing)
|
|
return c.conn.Close()
|
|
}
|
|
|
|
type Header struct {
|
|
Len uint16
|
|
Marker uint8
|
|
Version uint8
|
|
VrfId uint16
|
|
Command API_TYPE
|
|
}
|
|
|
|
func (h *Header) Serialize() ([]byte, error) {
|
|
buf := make([]byte, HeaderSize(h.Version))
|
|
binary.BigEndian.PutUint16(buf[0:], h.Len)
|
|
buf[2] = h.Marker
|
|
buf[3] = h.Version
|
|
if h.Version == 3 {
|
|
binary.BigEndian.PutUint16(buf[4:6], uint16(h.VrfId))
|
|
binary.BigEndian.PutUint16(buf[6:], uint16(h.Command))
|
|
} else {
|
|
binary.BigEndian.PutUint16(buf[4:], uint16(h.Command))
|
|
}
|
|
return buf, nil
|
|
}
|
|
|
|
func (h *Header) DecodeFromBytes(data []byte) error {
|
|
if uint16(len(data)) < 4 {
|
|
return fmt.Errorf("Not all ZAPI message header")
|
|
}
|
|
h.Len = binary.BigEndian.Uint16(data[0:2])
|
|
h.Marker = data[2]
|
|
h.Version = data[3]
|
|
if uint16(len(data)) < HeaderSize(h.Version) {
|
|
return fmt.Errorf("Not all ZAPI message header")
|
|
}
|
|
if h.Version == 3 {
|
|
h.VrfId = binary.BigEndian.Uint16(data[4:6])
|
|
h.Command = API_TYPE(binary.BigEndian.Uint16(data[6:8]))
|
|
} else {
|
|
h.Command = API_TYPE(binary.BigEndian.Uint16(data[4:6]))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type Body interface {
|
|
DecodeFromBytes([]byte, uint8) error
|
|
Serialize() ([]byte, error)
|
|
String() string
|
|
}
|
|
|
|
type HelloBody struct {
|
|
RedistDefault ROUTE_TYPE
|
|
}
|
|
|
|
func (b *HelloBody) DecodeFromBytes(data []byte, version uint8) error {
|
|
b.RedistDefault = ROUTE_TYPE(data[0])
|
|
return nil
|
|
}
|
|
|
|
func (b *HelloBody) Serialize() ([]byte, error) {
|
|
return []byte{uint8(b.RedistDefault)}, nil
|
|
}
|
|
|
|
func (b *HelloBody) String() string {
|
|
return fmt.Sprintf("route_type: %d", b.RedistDefault)
|
|
}
|
|
|
|
type RedistributeBody struct {
|
|
Redist ROUTE_TYPE
|
|
}
|
|
|
|
func (b *RedistributeBody) DecodeFromBytes(data []byte, version uint8) error {
|
|
b.Redist = ROUTE_TYPE(data[0])
|
|
return nil
|
|
}
|
|
|
|
func (b *RedistributeBody) Serialize() ([]byte, error) {
|
|
return []byte{uint8(b.Redist)}, nil
|
|
}
|
|
|
|
func (b *RedistributeBody) String() string {
|
|
return fmt.Sprintf("route_type: %d", b.Redist)
|
|
}
|
|
|
|
type InterfaceUpdateBody struct {
|
|
Name string
|
|
Index uint32
|
|
Status INTERFACE_STATUS
|
|
Flags uint64
|
|
Metric uint32
|
|
MTU uint32
|
|
MTU6 uint32
|
|
Bandwidth uint32
|
|
Linktype LINK_TYPE
|
|
HardwareAddr net.HardwareAddr
|
|
}
|
|
|
|
func (b *InterfaceUpdateBody) DecodeFromBytes(data []byte, version uint8) 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])
|
|
data = data[29:]
|
|
if version > 2 {
|
|
b.Linktype = LINK_TYPE(binary.BigEndian.Uint32(data[:4]))
|
|
data = data[4:]
|
|
}
|
|
l := binary.BigEndian.Uint32(data[:4])
|
|
if l > 0 {
|
|
if len(data) < 4+int(l) {
|
|
return fmt.Errorf("lack of bytes. need %d but %d", 4+l, len(data))
|
|
}
|
|
b.HardwareAddr = data[4 : 4+l]
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (b *InterfaceUpdateBody) Serialize() ([]byte, error) {
|
|
return []byte{}, nil
|
|
}
|
|
|
|
func (b *InterfaceUpdateBody) String() string {
|
|
s := fmt.Sprintf("name: %s, idx: %d, status: %s, flags: %s, metric: %d, mtu: %d, mtu6: %d, bandwidth: %d, linktype: %s", b.Name, b.Index, b.Status, intfflag2string(b.Flags), b.Metric, b.MTU, b.MTU6, b.Bandwidth, b.Linktype)
|
|
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, version uint8) 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, version uint8) 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
|
|
Mtu uint32
|
|
Api API_TYPE
|
|
}
|
|
|
|
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...)
|
|
}
|
|
if b.Message&MESSAGE_MTU > 0 {
|
|
bbuf := make([]byte, 4)
|
|
binary.BigEndian.PutUint32(bbuf, b.Mtu)
|
|
buf = append(buf, bbuf...)
|
|
}
|
|
return buf, nil
|
|
}
|
|
|
|
func (b *IPRouteBody) DecodeFromBytes(data []byte, version uint8) 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)
|
|
|
|
pos := 4
|
|
buf := make([]byte, addrLen)
|
|
copy(buf, data[pos:pos+byteLen])
|
|
|
|
if isV4 {
|
|
b.Prefix = net.IP(buf).To4()
|
|
} else {
|
|
b.Prefix = net.IP(buf).To16()
|
|
}
|
|
|
|
pos += byteLen
|
|
|
|
rest := 0
|
|
var numNexthop int
|
|
if b.Message&MESSAGE_NEXTHOP > 0 {
|
|
numNexthop = int(data[pos])
|
|
// 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 b.Message&MESSAGE_MTU > 0 {
|
|
// mtu(4)
|
|
rest += 4
|
|
}
|
|
|
|
if len(data[pos:]) != rest {
|
|
return fmt.Errorf("message length invalid")
|
|
}
|
|
|
|
b.Nexthops = []net.IP{}
|
|
b.Ifindexs = []uint32{}
|
|
|
|
if b.Message&MESSAGE_NEXTHOP > 0 {
|
|
pos += 1
|
|
for i := 0; i < numNexthop; i++ {
|
|
addr := data[pos : pos+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
|
|
pos += int(addrLen + 1)
|
|
ifidx := binary.BigEndian.Uint32(data[pos : pos+4])
|
|
b.Ifindexs = append(b.Ifindexs, ifidx)
|
|
pos += 4
|
|
}
|
|
}
|
|
|
|
if b.Message&MESSAGE_DISTANCE > 0 {
|
|
b.Distance = data[pos]
|
|
pos += 1
|
|
}
|
|
if b.Message&MESSAGE_METRIC > 0 {
|
|
b.Metric = binary.BigEndian.Uint32(data[pos : pos+4])
|
|
pos += 4
|
|
}
|
|
if b.Message&MESSAGE_MTU > 0 {
|
|
b.Mtu = binary.BigEndian.Uint32(data[pos : pos+4])
|
|
pos += 4
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (b *IPRouteBody) String() string {
|
|
s := fmt.Sprintf("type: %s, flags: %s, message: %d, prefix: %s, length: %d, nexthop: %s, distance: %d, metric: %d, mtu: %d",
|
|
b.Type.String(), b.Flags.String(), b.Message, b.Prefix.String(), b.PrefixLength, b.Nexthops[0].String(), b.Distance, b.Metric, b.Mtu)
|
|
return s
|
|
}
|
|
|
|
type NexthopLookupBody struct {
|
|
Api API_TYPE
|
|
Addr net.IP
|
|
Metric uint32
|
|
Nexthops []*Nexthop
|
|
}
|
|
|
|
type Nexthop struct {
|
|
Ifname string
|
|
Ifindex uint32
|
|
Type NEXTHOP_FLAG
|
|
Addr net.IP
|
|
}
|
|
|
|
func (n *Nexthop) String() string {
|
|
s := fmt.Sprintf("type: %s, addr: %s, ifindex: %d, ifname: %s", n.Type.String(), n.Addr.String(), n.Ifindex, n.Ifname)
|
|
return s
|
|
}
|
|
|
|
func serializeNexthops(nexthops []*Nexthop, isV4 bool) ([]byte, error) {
|
|
buf := make([]byte, 0)
|
|
if len(nexthops) == 0 {
|
|
return buf, nil
|
|
}
|
|
buf = append(buf, byte(len(nexthops)))
|
|
|
|
for _, nh := range nexthops {
|
|
buf = append(buf, byte(nh.Type))
|
|
|
|
switch nh.Type {
|
|
case NEXTHOP_IFINDEX, NEXTHOP_IFNAME:
|
|
bbuf := make([]byte, 4)
|
|
binary.BigEndian.PutUint32(bbuf, nh.Ifindex)
|
|
buf = append(buf, bbuf...)
|
|
|
|
case NEXTHOP_IPV4, NEXTHOP_IPV6:
|
|
if isV4 {
|
|
buf = append(buf, nh.Addr.To4()...)
|
|
} else {
|
|
buf = append(buf, nh.Addr.To16()...)
|
|
}
|
|
|
|
case NEXTHOP_IPV4_IFINDEX, NEXTHOP_IPV4_IFNAME, NEXTHOP_IPV6_IFINDEX, NEXTHOP_IPV6_IFNAME:
|
|
if isV4 {
|
|
buf = append(buf, nh.Addr.To4()...)
|
|
} else {
|
|
buf = append(buf, nh.Addr.To16()...)
|
|
}
|
|
bbuf := make([]byte, 4)
|
|
binary.BigEndian.PutUint32(bbuf, nh.Ifindex)
|
|
buf = append(buf, bbuf...)
|
|
}
|
|
}
|
|
|
|
return buf, nil
|
|
}
|
|
|
|
func decodeNexthopsFromBytes(nexthops *[]*Nexthop, data []byte, isV4 bool) (int, error) {
|
|
addrLen := net.IPv4len
|
|
if !isV4 {
|
|
addrLen = net.IPv6len
|
|
}
|
|
|
|
numNexthop := int(data[0])
|
|
offset := 1
|
|
|
|
for i := 0; i < numNexthop; i++ {
|
|
nh := &Nexthop{}
|
|
nh.Type = NEXTHOP_FLAG(data[offset])
|
|
offset += 1
|
|
|
|
switch nh.Type {
|
|
case NEXTHOP_IFINDEX, NEXTHOP_IFNAME:
|
|
nh.Ifindex = binary.BigEndian.Uint32(data[offset : offset+4])
|
|
offset += 4
|
|
|
|
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
|
|
}
|
|
*nexthops = append(*nexthops, nh)
|
|
}
|
|
|
|
return offset, nil
|
|
}
|
|
|
|
func (b *NexthopLookupBody) Serialize() ([]byte, error) {
|
|
|
|
isV4 := b.Api == IPV4_NEXTHOP_LOOKUP
|
|
buf := make([]byte, 0)
|
|
|
|
if isV4 {
|
|
buf = append(buf, b.Addr.To4()...)
|
|
} else {
|
|
buf = append(buf, b.Addr.To16()...)
|
|
}
|
|
return buf, nil
|
|
}
|
|
|
|
func (b *NexthopLookupBody) DecodeFromBytes(data []byte, version uint8) error {
|
|
|
|
isV4 := b.Api == IPV4_NEXTHOP_LOOKUP
|
|
addrLen := net.IPv4len
|
|
if !isV4 {
|
|
addrLen = net.IPv6len
|
|
}
|
|
|
|
if len(data) < addrLen {
|
|
return fmt.Errorf("message length invalid")
|
|
}
|
|
|
|
buf := make([]byte, addrLen)
|
|
copy(buf, data[0:addrLen])
|
|
pos := addrLen
|
|
|
|
if isV4 {
|
|
b.Addr = net.IP(buf).To4()
|
|
} else {
|
|
b.Addr = net.IP(buf).To16()
|
|
}
|
|
|
|
if len(data[pos:]) > int(1+addrLen) {
|
|
b.Metric = binary.BigEndian.Uint32(data[pos : pos+4])
|
|
pos += 4
|
|
b.Nexthops = []*Nexthop{}
|
|
if nexthopsByteLen, err := decodeNexthopsFromBytes(&b.Nexthops, data[pos:], isV4); err != nil {
|
|
return err
|
|
} else {
|
|
pos += nexthopsByteLen
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (b *NexthopLookupBody) String() string {
|
|
s := fmt.Sprintf("addr: %s, metric: %d", b.Addr, b.Metric)
|
|
if len(b.Nexthops) > 0 {
|
|
for _, nh := range b.Nexthops {
|
|
s = s + fmt.Sprintf(", nexthop:{%s}", nh.String())
|
|
}
|
|
}
|
|
return s
|
|
}
|
|
|
|
type ImportLookupBody struct {
|
|
Api API_TYPE
|
|
PrefixLength uint8
|
|
Prefix net.IP
|
|
Addr net.IP
|
|
Metric uint32
|
|
Nexthops []*Nexthop
|
|
}
|
|
|
|
func (b *ImportLookupBody) Serialize() ([]byte, error) {
|
|
buf := make([]byte, 1)
|
|
buf[0] = b.PrefixLength
|
|
buf = append(buf, b.Addr.To4()...)
|
|
return buf, nil
|
|
}
|
|
|
|
func (b *ImportLookupBody) DecodeFromBytes(data []byte, version uint8) error {
|
|
isV4 := b.Api == IPV4_IMPORT_LOOKUP
|
|
addrLen := net.IPv4len
|
|
if !isV4 {
|
|
addrLen = net.IPv6len
|
|
}
|
|
|
|
if len(data) < addrLen {
|
|
return fmt.Errorf("message length invalid")
|
|
}
|
|
|
|
buf := make([]byte, addrLen)
|
|
copy(buf, data[0:addrLen])
|
|
pos := addrLen
|
|
|
|
b.Addr = net.IP(buf).To4()
|
|
|
|
if len(data[pos:]) > int(1+addrLen) {
|
|
b.Metric = binary.BigEndian.Uint32(data[pos : pos+4])
|
|
pos += 4
|
|
b.Nexthops = []*Nexthop{}
|
|
if nexthopsByteLen, err := decodeNexthopsFromBytes(&b.Nexthops, data[pos:], isV4); err != nil {
|
|
return err
|
|
} else {
|
|
pos += nexthopsByteLen
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (b *ImportLookupBody) String() string {
|
|
s := fmt.Sprintf("addr: %s, metric: %d", b.Addr, b.Metric)
|
|
if len(b.Nexthops) > 0 {
|
|
for _, nh := range b.Nexthops {
|
|
s = s + fmt.Sprintf(", nexthop:{%s}", nh.String())
|
|
}
|
|
}
|
|
return s
|
|
}
|
|
|
|
type RegisteredNexthop struct {
|
|
Connected uint8
|
|
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
|
|
}
|
|
|
|
func (n *RegisteredNexthop) Len() int {
|
|
// Connected (1 byte) + Address Family (2 bytes) + Prefix Length (1 byte) + Prefix (variable)
|
|
if n.Family == uint16(syscall.AF_INET) {
|
|
return 4 + net.IPv4len
|
|
} else {
|
|
return 4 + net.IPv6len
|
|
}
|
|
}
|
|
|
|
func (n *RegisteredNexthop) Serialize() ([]byte, error) {
|
|
// Connected (1 byte)
|
|
buf := make([]byte, 4)
|
|
buf[0] = byte(n.Connected)
|
|
|
|
// Address Family (2 bytes)
|
|
binary.BigEndian.PutUint16(buf[1:3], n.Family)
|
|
|
|
// Prefix Length (1 byte) + Prefix (variable)
|
|
switch n.Family {
|
|
case uint16(syscall.AF_INET):
|
|
buf[3] = byte(net.IPv4len * 8)
|
|
buf = append(buf, n.Prefix.To4()...)
|
|
case uint16(syscall.AF_INET6):
|
|
buf[3] = byte(net.IPv6len * 8)
|
|
buf = append(buf, n.Prefix.To16()...)
|
|
default:
|
|
return nil, fmt.Errorf("invalid address family: %d", n.Family)
|
|
}
|
|
|
|
return buf, nil
|
|
}
|
|
|
|
func (n *RegisteredNexthop) DecodeFromBytes(data []byte) error {
|
|
// Connected (1 byte)
|
|
n.Connected = uint8(data[0])
|
|
offset := 1
|
|
|
|
// Address Family (2 bytes)
|
|
n.Family = binary.BigEndian.Uint16(data[offset : offset+2])
|
|
isV4 := n.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 {
|
|
n.Prefix = net.IP(data[offset : offset+addrLen]).To4()
|
|
} else {
|
|
n.Prefix = net.IP(data[offset : offset+addrLen]).To16()
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (n *RegisteredNexthop) String() string {
|
|
return fmt.Sprintf("connected: %d, family: %d, prefix: %s", n.Connected, n.Family, n.Prefix.String())
|
|
}
|
|
|
|
type NexthopRegisterBody struct {
|
|
Api API_TYPE
|
|
Nexthops []*RegisteredNexthop
|
|
}
|
|
|
|
func (b *NexthopRegisterBody) Serialize() ([]byte, error) {
|
|
buf := make([]byte, 0)
|
|
|
|
// List of Registered Nexthops
|
|
for _, nh := range b.Nexthops {
|
|
nhBuf, err := nh.Serialize()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
buf = append(buf, nhBuf...)
|
|
}
|
|
|
|
return buf, nil
|
|
}
|
|
|
|
func (b *NexthopRegisterBody) DecodeFromBytes(data []byte, version uint8) error {
|
|
offset := 0
|
|
|
|
// List of Registered Nexthops
|
|
b.Nexthops = []*RegisteredNexthop{}
|
|
for len(data[offset:]) > 0 {
|
|
nh := new(RegisteredNexthop)
|
|
err := nh.DecodeFromBytes(data[offset:])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
b.Nexthops = append(b.Nexthops, nh)
|
|
|
|
offset += nh.Len()
|
|
if len(data) < offset {
|
|
break
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (b *NexthopRegisterBody) String() string {
|
|
s := make([]string, 0)
|
|
for _, nh := range b.Nexthops {
|
|
s = append(s, fmt.Sprintf("nexthop:{%s}", nh.String()))
|
|
}
|
|
return strings.Join(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
|
|
|
|
// List of Nexthops
|
|
b.Nexthops = []*Nexthop{}
|
|
if nexthopsByteLen, err := decodeNexthopsFromBytes(&b.Nexthops, data[offset:], isV4); err != nil {
|
|
return err
|
|
} else {
|
|
offset += nexthopsByteLen
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
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)) + HeaderSize(m.Header.Version)
|
|
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{}
|
|
case IPV4_ROUTE_ADD, IPV6_ROUTE_ADD, IPV4_ROUTE_DELETE, IPV6_ROUTE_DELETE:
|
|
m.Body = &IPRouteBody{Api: m.Header.Command}
|
|
log.WithFields(log.Fields{
|
|
"Topic": "Zebra",
|
|
}).Debugf("ipv4/v6 route add/delete message received: %v", data)
|
|
case IPV4_NEXTHOP_LOOKUP, IPV6_NEXTHOP_LOOKUP:
|
|
m.Body = &NexthopLookupBody{Api: m.Header.Command}
|
|
log.WithFields(log.Fields{
|
|
"Topic": "Zebra",
|
|
}).Debugf("ipv4/v6 nexthop lookup received: %v", data)
|
|
case IPV4_IMPORT_LOOKUP:
|
|
m.Body = &ImportLookupBody{Api: m.Header.Command}
|
|
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)
|
|
}
|
|
err := m.Body.DecodeFromBytes(data, m.Header.Version)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return m, nil
|
|
}
|