summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--zebra/zapi.go579
1 files changed, 440 insertions, 139 deletions
diff --git a/zebra/zapi.go b/zebra/zapi.go
index 0beb3ccc..6998bd4e 100644
--- a/zebra/zapi.go
+++ b/zebra/zapi.go
@@ -103,7 +103,7 @@ const VRF_DEFAULT = 0
func HeaderSize(version uint8) uint16 {
switch version {
- case 3:
+ case 3, 4:
return 8
default:
return 6
@@ -521,8 +521,10 @@ func NewClient(network, address string, typ ROUTE_TYPE, version uint8) (*Client,
}
outgoing := make(chan *Message)
incoming := make(chan *Message, 64)
- if version != 3 {
+ if version < 2 {
version = 2
+ } else if version > 4 {
+ version = 4
}
c := &Client{
@@ -657,10 +659,14 @@ func (c *Client) Send(m *Message) {
}
func (c *Client) SendCommand(command API_TYPE, vrfId uint16, body Body) error {
+ var marker uint8 = HEADER_MARKER
+ if c.Version >= 4 {
+ marker = FRR_HEADER_MARKER
+ }
m := &Message{
Header: Header{
Len: HeaderSize(c.Version),
- Marker: HEADER_MARKER,
+ Marker: marker,
Version: c.Version,
VrfId: vrfId,
Command: command,
@@ -673,29 +679,56 @@ func (c *Client) SendCommand(command API_TYPE, vrfId uint16, body Body) error {
func (c *Client) SendHello() error {
if c.redistDefault > 0 {
+ command := HELLO
body := &HelloBody{
RedistDefault: c.redistDefault,
+ Instance: 0,
+ }
+ if c.Version >= 4 {
+ command = FRR_HELLO
}
- return c.SendCommand(HELLO, VRF_DEFAULT, body)
+ return c.SendCommand(command, VRF_DEFAULT, body)
}
return nil
}
func (c *Client) SendRouterIDAdd() error {
- return c.SendCommand(ROUTER_ID_ADD, VRF_DEFAULT, nil)
+ command := ROUTER_ID_ADD
+ if c.Version >= 4 {
+ command = FRR_ROUTER_ID_ADD
+ }
+ return c.SendCommand(command, VRF_DEFAULT, nil)
}
func (c *Client) SendInterfaceAdd() error {
- return c.SendCommand(INTERFACE_ADD, VRF_DEFAULT, nil)
+ command := INTERFACE_ADD
+ if c.Version >= 4 {
+ command = FRR_INTERFACE_ADD
+ }
+ return c.SendCommand(command, VRF_DEFAULT, nil)
}
func (c *Client) SendRedistribute(t ROUTE_TYPE, vrfId uint16) error {
+ command := REDISTRIBUTE_ADD
if c.redistDefault != t {
- body := &RedistributeBody{
- Redist: t,
+ bodies := make([]*RedistributeBody, 0)
+ if c.Version <= 3 {
+ bodies = append(bodies, &RedistributeBody{
+ Redist: t,
+ })
+ } else { // version >= 4
+ command = FRR_REDISTRIBUTE_ADD
+ for _, afi := range []AFI{AFI_IP, AFI_IP6} {
+ bodies = append(bodies, &RedistributeBody{
+ Afi: afi,
+ Redist: t,
+ Instance: 0,
+ })
+ }
}
- if e := c.SendCommand(REDISTRIBUTE_ADD, vrfId, body); e != nil {
- return e
+
+ for _, body := range bodies {
+ return c.SendCommand(command, vrfId, body)
}
}
@@ -703,14 +736,15 @@ func (c *Client) SendRedistribute(t ROUTE_TYPE, vrfId uint16) error {
}
func (c *Client) SendRedistributeDelete(t ROUTE_TYPE) error {
-
if t < ROUTE_MAX {
+ command := REDISTRIBUTE_DELETE
+ if c.Version >= 4 {
+ command = FRR_REDISTRIBUTE_DELETE
+ }
body := &RedistributeBody{
Redist: t,
}
- if e := c.SendCommand(REDISTRIBUTE_DELETE, VRF_DEFAULT, body); e != nil {
- return e
- }
+ return c.SendCommand(command, VRF_DEFAULT, body)
} else {
return fmt.Errorf("unknown route type: %d", t)
}
@@ -732,14 +766,17 @@ type Header struct {
func (h *Header) Serialize() ([]byte, error) {
buf := make([]byte, HeaderSize(h.Version))
- binary.BigEndian.PutUint16(buf[0:], h.Len)
+ binary.BigEndian.PutUint16(buf[0:2], h.Len)
buf[2] = h.Marker
buf[3] = h.Version
- if h.Version == 3 {
+ switch h.Version {
+ case 2:
+ binary.BigEndian.PutUint16(buf[4:6], uint16(h.Command))
+ case 3, 4:
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))
+ binary.BigEndian.PutUint16(buf[6:8], uint16(h.Command))
+ default:
+ return nil, fmt.Errorf("Unsupported ZAPI version: %d", h.Version)
}
return buf, nil
}
@@ -754,11 +791,14 @@ func (h *Header) DecodeFromBytes(data []byte) error {
if uint16(len(data)) < HeaderSize(h.Version) {
return fmt.Errorf("Not all ZAPI message header")
}
- if h.Version == 3 {
+ switch h.Version {
+ case 2:
+ h.Command = API_TYPE(binary.BigEndian.Uint16(data[4:6]))
+ case 3, 4:
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]))
+ default:
+ return fmt.Errorf("Unsupported ZAPI version: %d", h.Version)
}
return nil
}
@@ -788,36 +828,68 @@ func (b *UnknownBody) String() string {
type HelloBody struct {
RedistDefault ROUTE_TYPE
+ Instance uint16
}
func (b *HelloBody) DecodeFromBytes(data []byte, version uint8) error {
b.RedistDefault = ROUTE_TYPE(data[0])
+ if version >= 4 {
+ b.Instance = binary.BigEndian.Uint16(data[1:3])
+ }
return nil
}
func (b *HelloBody) Serialize(version uint8) ([]byte, error) {
- return []byte{uint8(b.RedistDefault)}, nil
+ if version <= 3 {
+ return []byte{uint8(b.RedistDefault)}, nil
+ } else { // version >= 4
+ buf := make([]byte, 3, 3)
+ buf[0] = uint8(b.RedistDefault)
+ binary.BigEndian.PutUint16(buf[1:3], b.Instance)
+ return buf, nil
+
+ }
}
func (b *HelloBody) String() string {
- return fmt.Sprintf("route_type: %d", b.RedistDefault)
+ return fmt.Sprintf(
+ "route_type: %s, instance :%d",
+ b.RedistDefault.String(), b.Instance)
}
type RedistributeBody struct {
- Redist ROUTE_TYPE
+ Afi AFI
+ Redist ROUTE_TYPE
+ Instance uint16
}
func (b *RedistributeBody) DecodeFromBytes(data []byte, version uint8) error {
- b.Redist = ROUTE_TYPE(data[0])
+ if version <= 3 {
+ b.Redist = ROUTE_TYPE(data[0])
+ } else { // version >= 4
+ b.Afi = AFI(data[0])
+ b.Redist = ROUTE_TYPE(data[1])
+ b.Instance = binary.BigEndian.Uint16(data[2:4])
+ }
return nil
}
func (b *RedistributeBody) Serialize(version uint8) ([]byte, error) {
- return []byte{uint8(b.Redist)}, nil
+ if version <= 3 {
+ return []byte{uint8(b.Redist)}, nil
+ } else { // version >= 4
+ buf := make([]byte, 4, 4)
+ buf[0] = uint8(b.Afi)
+ buf[1] = uint8(b.Redist)
+ binary.BigEndian.PutUint16(buf[2:4], b.Instance)
+ return buf, nil
+ }
}
func (b *RedistributeBody) String() string {
- return fmt.Sprintf("route_type: %d", b.Redist)
+ return fmt.Sprintf(
+ "afi: %s, route_type: %s, instance :%d",
+ b.Afi.String(), b.Redist.String(), b.Instance)
}
type InterfaceUpdateBody struct {
@@ -825,7 +897,10 @@ type InterfaceUpdateBody struct {
Index uint32
Status INTERFACE_STATUS
Flags uint64
+ PTMEnable PTM_ENABLE
+ PTMStatus PTM_STATUS
Metric uint32
+ Speed uint32
MTU uint32
MTU6 uint32
Bandwidth uint32
@@ -840,17 +915,27 @@ func (b *InterfaceUpdateBody) DecodeFromBytes(data []byte, version uint8) error
b.Name = strings.Trim(string(data[:INTERFACE_NAMSIZ]), "\u0000")
data = data[INTERFACE_NAMSIZ:]
- b.Index = binary.BigEndian.Uint32(data[:4])
+ b.Index = binary.BigEndian.Uint32(data[0: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:]
+ if version >= 4 {
+ b.PTMEnable = PTM_ENABLE(data[13])
+ b.PTMStatus = PTM_STATUS(data[14])
+ b.Metric = binary.BigEndian.Uint32(data[15:19])
+ b.Speed = binary.BigEndian.Uint32(data[19:23])
+ data = data[23:]
+ } else {
+ b.Metric = binary.BigEndian.Uint32(data[13:17])
+ data = data[17:]
+ }
+ b.MTU = binary.BigEndian.Uint32(data[0:4])
+ b.MTU6 = binary.BigEndian.Uint32(data[4:8])
+ b.Bandwidth = binary.BigEndian.Uint32(data[8:12])
+ if version >= 3 {
+ b.Linktype = LINK_TYPE(binary.BigEndian.Uint32(data[12:16]))
+ data = data[16:]
+ } else {
+ data = data[12:]
}
l := binary.BigEndian.Uint32(data[:4])
if l > 0 {
@@ -867,9 +952,11 @@ func (b *InterfaceUpdateBody) Serialize(version uint8) ([]byte, error) {
}
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)
+ s := fmt.Sprintf(
+ "name: %s, idx: %d, status: %s, flags: %s, ptm_enable: %s, ptm_status: %s, metric: %d, speed: %d, mtu: %d, mtu6: %d, bandwidth: %d, linktype: %s",
+ b.Name, b.Index, b.Status.String(), intfflag2string(b.Flags), b.PTMEnable.String(), b.PTMStatus.String(), b.Metric, b.Speed, b.MTU, b.MTU6, b.Bandwidth, b.Linktype.String())
if len(b.HardwareAddr) > 0 {
- return s + fmt.Sprintf(", mac: %s", b.HardwareAddr)
+ return s + fmt.Sprintf(", mac: %s", b.HardwareAddr.String())
}
return s
}
@@ -906,7 +993,9 @@ func (b *InterfaceAddressUpdateBody) Serialize(version uint8) ([]byte, error) {
}
func (b *InterfaceAddressUpdateBody) String() string {
- return fmt.Sprintf("idx: %d, flags: %d, addr: %s/%d", b.Index, b.Flags, b.Prefix, b.Length)
+ return fmt.Sprintf(
+ "idx: %d, flags: %d, addr: %s/%d",
+ b.Index, b.Flags.String(), b.Prefix.String(), b.Length)
}
type RouterIDUpdateBody struct {
@@ -935,61 +1024,81 @@ func (b *RouterIDUpdateBody) Serialize(version uint8) ([]byte, error) {
}
func (b *RouterIDUpdateBody) String() string {
- return fmt.Sprintf("id: %s/%d", b.Prefix, b.Length)
+ return fmt.Sprintf("id: %s/%d", b.Prefix.String(), b.Length)
}
type IPRouteBody struct {
- Type ROUTE_TYPE
- Flags FLAG
- Message MESSAGE_FLAG
- SAFI SAFI
- Prefix net.IP
- PrefixLength uint8
- Nexthops []net.IP
- Ifindexs []uint32
- Distance uint8
- Metric uint32
- Mtu uint32
- Api API_TYPE
+ Type ROUTE_TYPE
+ Instance uint16
+ Flags FLAG
+ Message MESSAGE_FLAG
+ SAFI SAFI
+ Prefix net.IP
+ PrefixLength uint8
+ SrcPrefix net.IP
+ SrcPrefixLength uint8
+ Nexthops []net.IP
+ Ifindexs []uint32
+ Distance uint8
+ Metric uint32
+ Mtu uint32
+ Tag uint32
+ Api API_TYPE
}
func (b *IPRouteBody) Serialize(version uint8) ([]byte, error) {
- buf := make([]byte, 5)
- buf[0] = uint8(b.Type)
- buf[1] = uint8(b.Flags)
- buf[2] = uint8(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...)
+
+ var buf []byte
+ nhfIPv4 := uint8(NEXTHOP_IPV4)
+ nhfIPv6 := uint8(NEXTHOP_IPV6)
+ nhfIndx := uint8(NEXTHOP_IFINDEX)
+ nhfBlkH := uint8(NEXTHOP_BLACKHOLE)
+ if version <= 3 {
+ buf = make([]byte, 5)
+ buf[0] = uint8(b.Type)
+ buf[1] = uint8(b.Flags)
+ buf[2] = uint8(b.Message)
+ binary.BigEndian.PutUint16(buf[3:5], uint16(b.SAFI))
+ } else { // version >= 4
+ buf = make([]byte, 10)
+ buf[0] = uint8(b.Type)
+ binary.BigEndian.PutUint16(buf[1:3], uint16(b.Instance))
+ binary.BigEndian.PutUint32(buf[3:7], uint32(b.Flags))
+ buf[7] = uint8(b.Message)
+ binary.BigEndian.PutUint16(buf[8:10], uint16(b.SAFI))
+ nhfIPv4 = uint8(FRR_NEXTHOP_IPV4)
+ nhfIPv6 = uint8(FRR_NEXTHOP_IPV6)
+ nhfIndx = uint8(FRR_NEXTHOP_IFINDEX)
+ nhfBlkH = uint8(FRR_NEXTHOP_BLACKHOLE)
+ }
+ byteLen := (int(b.PrefixLength) + 7) / 8
+ buf = append(buf, b.PrefixLength)
+ buf = append(buf, b.Prefix[:byteLen]...)
+ if b.Message&FRR_MESSAGE_SRCPFX > 0 {
+ byteLen = (int(b.SrcPrefixLength) + 7) / 8
+ buf = append(buf, b.SrcPrefixLength)
+ buf = append(buf, b.SrcPrefix[:byteLen]...)
+ }
if b.Message&MESSAGE_NEXTHOP > 0 {
if b.Flags&FLAG_BLACKHOLE > 0 {
- buf = append(buf, []byte{1, uint8(NEXTHOP_BLACKHOLE)}...)
+ buf = append(buf, []byte{1, nhfBlkH}...)
} 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, nhfIPv4)
buf = append(buf, v.To4()...)
} else {
- buf = append(buf, uint8(NEXTHOP_IPV6))
+ buf = append(buf, nhfIPv6)
buf = append(buf, v.To16()...)
}
}
for _, v := range b.Ifindexs {
- buf = append(buf, uint8(NEXTHOP_IFINDEX))
+ buf = append(buf, nhfIndx)
bbuf := make([]byte, 4)
binary.BigEndian.PutUint32(bbuf, v)
buf = append(buf, bbuf...)
@@ -1004,46 +1113,86 @@ func (b *IPRouteBody) Serialize(version uint8) ([]byte, error) {
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...)
+ if version <= 3 {
+ if b.Message&MESSAGE_MTU > 0 {
+ bbuf := make([]byte, 4)
+ binary.BigEndian.PutUint32(bbuf, b.Mtu)
+ buf = append(buf, bbuf...)
+ }
+ if b.Message&MESSAGE_TAG > 0 {
+ bbuf := make([]byte, 4)
+ binary.BigEndian.PutUint32(bbuf, b.Tag)
+ buf = append(buf, bbuf...)
+ }
+ } else { // version >= 4
+ if b.Message&FRR_MESSAGE_TAG > 0 {
+ bbuf := make([]byte, 4)
+ binary.BigEndian.PutUint32(bbuf, b.Tag)
+ buf = append(buf, bbuf...)
+ }
+ if b.Message&FRR_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
+ isV4 := true
+ if version <= 3 {
+ isV4 = b.Api == IPV4_ROUTE_ADD || b.Api == IPV4_ROUTE_DELETE
+ } else {
+ isV4 = b.Api == FRR_REDISTRIBUTE_IPV4_ADD || b.Api == FRR_REDISTRIBUTE_IPV4_DEL
+ }
var addrLen uint8 = net.IPv4len
if !isV4 {
addrLen = net.IPv6len
}
b.Type = ROUTE_TYPE(data[0])
- b.Flags = FLAG(data[1])
- b.Message = MESSAGE_FLAG(data[2])
- b.PrefixLength = data[3]
+ if version <= 3 {
+ b.Flags = FLAG(data[1])
+ data = data[2:]
+ } else { // version >= 4
+ b.Instance = binary.BigEndian.Uint16(data[1:3])
+ b.Flags = FLAG(binary.BigEndian.Uint32(data[3:7]))
+ data = data[7:]
+ }
+
+ b.Message = MESSAGE_FLAG(data[0])
b.SAFI = SAFI(SAFI_UNICAST)
+ b.PrefixLength = data[1]
if b.PrefixLength > addrLen*8 {
return fmt.Errorf("prefix length is greater than %d", addrLen*8)
}
-
- byteLen := int((b.PrefixLength + 7) / 8)
-
- pos := 4
+ pos := 2
buf := make([]byte, addrLen)
+ byteLen := int((b.PrefixLength + 7) / 8)
copy(buf, data[pos:pos+byteLen])
-
if isV4 {
b.Prefix = net.IP(buf).To4()
} else {
b.Prefix = net.IP(buf).To16()
}
-
pos += byteLen
+ if b.Message&FRR_MESSAGE_SRCPFX > 0 {
+ b.SrcPrefixLength = data[pos]
+ pos += 1
+ buf = make([]byte, addrLen)
+ byteLen = int((b.SrcPrefixLength + 7) / 8)
+ copy(buf, data[pos:pos+byteLen])
+ if isV4 {
+ b.SrcPrefix = net.IP(buf).To4()
+ } else {
+ b.SrcPrefix = net.IP(buf).To16()
+ }
+ pos += byteLen
+ }
+
rest := 0
var numNexthop int
if b.Message&MESSAGE_NEXTHOP > 0 {
@@ -1051,20 +1200,32 @@ func (b *IPRouteBody) DecodeFromBytes(data []byte, version uint8) error {
// 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 version <= 3 {
+ if b.Message&MESSAGE_MTU > 0 {
+ // mtu(4)
+ rest += 4
+ }
+ if b.Message&MESSAGE_TAG > 0 {
+ // tag(4)
+ rest += 4
+ }
+ } else { // version >= 4
+ if b.Message&FRR_MESSAGE_TAG > 0 {
+ // tag(4)
+ rest += 4
+ }
+ if b.Message&FRR_MESSAGE_MTU > 0 {
+ // mtu(4)
+ rest += 4
+ }
}
if len(data[pos:]) != rest {
@@ -1102,23 +1263,48 @@ func (b *IPRouteBody) DecodeFromBytes(data []byte, version uint8) error {
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
+ if version <= 3 {
+ if b.Message&MESSAGE_MTU > 0 {
+ b.Mtu = binary.BigEndian.Uint32(data[pos : pos+4])
+ pos += 4
+ }
+ if b.Message&MESSAGE_TAG > 0 {
+ b.Tag = binary.BigEndian.Uint32(data[pos : pos+4])
+ pos += 4
+ }
+ } else {
+ if b.Message&FRR_MESSAGE_TAG > 0 {
+ b.Tag = binary.BigEndian.Uint32(data[pos : pos+4])
+ pos += 4
+ }
+ if b.Message&FRR_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
+ s := fmt.Sprintf(
+ "type: %s, instance: %d, flags: %s, message: %d, safi: %s, prefix: %s/%d, src_prefix: %s/%d",
+ b.Type.String(), b.Instance, b.Flags.String(), b.Message, b.SAFI.String(), b.Prefix.String(), b.PrefixLength, b.SrcPrefix.String(), b.SrcPrefixLength)
+ for i, nh := range b.Nexthops {
+ s += fmt.Sprintf(", nexthops[%d]: %s", i, nh.String())
+ }
+ for i, idx := range b.Ifindexs {
+ s += fmt.Sprintf(", ifindex[%d]: %d", i, idx)
+ }
+ return s + fmt.Sprintf(
+ ", distance: %d, metric: %d, mtu: %d, tag: %d",
+ b.Distance, b.Metric, b.Mtu, b.Tag)
}
type NexthopLookupBody struct {
Api API_TYPE
Addr net.IP
+ Distance uint8
Metric uint32
Nexthops []*Nexthop
}
@@ -1131,34 +1317,63 @@ type Nexthop struct {
}
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)
+ 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) {
+func serializeNexthops(nexthops []*Nexthop, isV4 bool, version uint8) ([]byte, error) {
buf := make([]byte, 0)
if len(nexthops) == 0 {
return buf, nil
}
buf = append(buf, byte(len(nexthops)))
+ nhIfindex := NEXTHOP_IFINDEX
+ nhIfname := NEXTHOP_IFNAME
+ nhIPv4 := NEXTHOP_IPV4
+ nhIPv4Ifindex := NEXTHOP_IPV4_IFINDEX
+ nhIPv4Ifname := NEXTHOP_IPV4_IFNAME
+ nhIPv6 := NEXTHOP_IPV6
+ nhIPv6Ifindex := NEXTHOP_IPV6_IFINDEX
+ nhIPv6Ifname := NEXTHOP_IPV6_IFNAME
+ if version >= 4 {
+ nhIfindex = FRR_NEXTHOP_IFINDEX
+ nhIfname = NEXTHOP_FLAG(0)
+ nhIPv4 = FRR_NEXTHOP_IPV4
+ nhIPv4Ifindex = FRR_NEXTHOP_IPV4_IFINDEX
+ nhIPv4Ifname = NEXTHOP_FLAG(0)
+ nhIPv6 = FRR_NEXTHOP_IPV6
+ nhIPv6Ifindex = FRR_NEXTHOP_IPV6_IFINDEX
+ nhIPv6Ifname = NEXTHOP_FLAG(0)
+ }
+
for _, nh := range nexthops {
buf = append(buf, byte(nh.Type))
switch nh.Type {
- case NEXTHOP_IFINDEX, NEXTHOP_IFNAME:
+ case nhIfindex, nhIfname:
bbuf := make([]byte, 4)
binary.BigEndian.PutUint32(bbuf, nh.Ifindex)
buf = append(buf, bbuf...)
- case NEXTHOP_IPV4, NEXTHOP_IPV6:
+ case nhIPv4, nhIPv6:
if isV4 {
buf = append(buf, nh.Addr.To4()...)
} else {
buf = append(buf, nh.Addr.To16()...)
}
+ if version >= 4 {
+ // On FRRouting version 3.0 or later, NEXTHOP_IPV4 and
+ // NEXTHOP_IPV6 have the same structure with
+ // NEXTHOP_TYPE_IPV4_IFINDEX and NEXTHOP_TYPE_IPV6_IFINDEX.
+ bbuf := make([]byte, 4)
+ binary.BigEndian.PutUint32(bbuf, nh.Ifindex)
+ buf = append(buf, bbuf...)
+ }
- case NEXTHOP_IPV4_IFINDEX, NEXTHOP_IPV4_IFNAME, NEXTHOP_IPV6_IFINDEX, NEXTHOP_IPV6_IFNAME:
+ case nhIPv4Ifindex, nhIPv4Ifname, nhIPv6Ifindex, nhIPv6Ifname:
if isV4 {
buf = append(buf, nh.Addr.To4()...)
} else {
@@ -1173,11 +1388,29 @@ func serializeNexthops(nexthops []*Nexthop, isV4 bool) ([]byte, error) {
return buf, nil
}
-func decodeNexthopsFromBytes(nexthops *[]*Nexthop, data []byte, isV4 bool) (int, error) {
+func decodeNexthopsFromBytes(nexthops *[]*Nexthop, data []byte, isV4 bool, version uint8) (int, error) {
addrLen := net.IPv4len
if !isV4 {
addrLen = net.IPv6len
}
+ nhIfindex := NEXTHOP_IFINDEX
+ nhIfname := NEXTHOP_IFNAME
+ nhIPv4 := NEXTHOP_IPV4
+ nhIPv4Ifindex := NEXTHOP_IPV4_IFINDEX
+ nhIPv4Ifname := NEXTHOP_IPV4_IFNAME
+ nhIPv6 := NEXTHOP_IPV6
+ nhIPv6Ifindex := NEXTHOP_IPV6_IFINDEX
+ nhIPv6Ifname := NEXTHOP_IPV6_IFNAME
+ if version >= 4 {
+ nhIfindex = FRR_NEXTHOP_IFINDEX
+ nhIfname = NEXTHOP_FLAG(0)
+ nhIPv4 = FRR_NEXTHOP_IPV4
+ nhIPv4Ifindex = FRR_NEXTHOP_IPV4_IFINDEX
+ nhIPv4Ifname = NEXTHOP_FLAG(0)
+ nhIPv6 = FRR_NEXTHOP_IPV6
+ nhIPv6Ifindex = FRR_NEXTHOP_IPV6_IFINDEX
+ nhIPv6Ifname = NEXTHOP_FLAG(0)
+ }
numNexthop := int(data[0])
offset := 1
@@ -1188,19 +1421,26 @@ func decodeNexthopsFromBytes(nexthops *[]*Nexthop, data []byte, isV4 bool) (int,
offset += 1
switch nh.Type {
- case NEXTHOP_IFINDEX, NEXTHOP_IFNAME:
+ case nhIfindex, nhIfname:
nh.Ifindex = binary.BigEndian.Uint32(data[offset : offset+4])
offset += 4
- case NEXTHOP_IPV4, NEXTHOP_IPV6:
+ case nhIPv4, nhIPv6:
if isV4 {
nh.Addr = net.IP(data[offset : offset+addrLen]).To4()
} else {
nh.Addr = net.IP(data[offset : offset+addrLen]).To16()
}
offset += addrLen
+ if version >= 4 {
+ // On FRRouting version 3.0 or later, NEXTHOP_IPV4 and
+ // NEXTHOP_IPV6 have the same structure with
+ // NEXTHOP_TYPE_IPV4_IFINDEX and NEXTHOP_TYPE_IPV6_IFINDEX.
+ nh.Ifindex = binary.BigEndian.Uint32(data[offset : offset+4])
+ offset += 4
+ }
- case NEXTHOP_IPV4_IFINDEX, NEXTHOP_IPV4_IFNAME, NEXTHOP_IPV6_IFINDEX, NEXTHOP_IPV6_IFNAME:
+ case nhIPv4Ifindex, nhIPv4Ifname, nhIPv6Ifindex, nhIPv6Ifname:
if isV4 {
nh.Addr = net.IP(data[offset : offset+addrLen]).To4()
} else {
@@ -1217,8 +1457,13 @@ func decodeNexthopsFromBytes(nexthops *[]*Nexthop, data []byte, isV4 bool) (int,
}
func (b *NexthopLookupBody) Serialize(version uint8) ([]byte, error) {
+ isV4 := false
+ if version <= 3 {
+ isV4 = b.Api == IPV4_NEXTHOP_LOOKUP
+ } else { // version >= 4
+ isV4 = b.Api == FRR_IPV4_NEXTHOP_LOOKUP_MRIB
+ }
- isV4 := b.Api == IPV4_NEXTHOP_LOOKUP
buf := make([]byte, 0)
if isV4 {
@@ -1230,8 +1475,12 @@ func (b *NexthopLookupBody) Serialize(version uint8) ([]byte, error) {
}
func (b *NexthopLookupBody) DecodeFromBytes(data []byte, version uint8) error {
-
- isV4 := b.Api == IPV4_NEXTHOP_LOOKUP
+ isV4 := false
+ if version <= 3 {
+ isV4 = b.Api == IPV4_NEXTHOP_LOOKUP
+ } else { // version >= 4
+ isV4 = b.Api == FRR_IPV4_NEXTHOP_LOOKUP_MRIB
+ }
addrLen := net.IPv4len
if !isV4 {
addrLen = net.IPv6len
@@ -1251,11 +1500,16 @@ func (b *NexthopLookupBody) DecodeFromBytes(data []byte, version uint8) error {
b.Addr = net.IP(buf).To16()
}
+ if version >= 4 {
+ b.Distance = data[pos]
+ pos++
+ }
+
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 {
+ if nexthopsByteLen, err := decodeNexthopsFromBytes(&b.Nexthops, data[pos:], isV4, version); err != nil {
return err
} else {
pos += nexthopsByteLen
@@ -1266,7 +1520,9 @@ func (b *NexthopLookupBody) DecodeFromBytes(data []byte, version uint8) error {
}
func (b *NexthopLookupBody) String() string {
- s := fmt.Sprintf("addr: %s, metric: %d", b.Addr, b.Metric)
+ s := fmt.Sprintf(
+ "addr: %s, distance:%d, metric: %d",
+ b.Addr.String(), b.Distance, b.Metric)
if len(b.Nexthops) > 0 {
for _, nh := range b.Nexthops {
s = s + fmt.Sprintf(", nexthop:{%s}", nh.String())
@@ -1312,7 +1568,7 @@ func (b *ImportLookupBody) DecodeFromBytes(data []byte, version uint8) error {
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 {
+ if nexthopsByteLen, err := decodeNexthopsFromBytes(&b.Nexthops, data[pos:], isV4, version); err != nil {
return err
} else {
pos += nexthopsByteLen
@@ -1323,7 +1579,9 @@ func (b *ImportLookupBody) DecodeFromBytes(data []byte, version uint8) error {
}
func (b *ImportLookupBody) String() string {
- s := fmt.Sprintf("addr: %s, metric: %d", b.Addr, b.Metric)
+ s := fmt.Sprintf(
+ "prefix: %s/%d, addr: %s, metric: %d",
+ b.Prefix.String(), b.PrefixLength, b.Addr.String(), b.Metric)
if len(b.Nexthops) > 0 {
for _, nh := range b.Nexthops {
s = s + fmt.Sprintf(", nexthop:{%s}", nh.String())
@@ -1400,7 +1658,9 @@ func (n *RegisteredNexthop) DecodeFromBytes(data []byte) error {
}
func (n *RegisteredNexthop) String() string {
- return fmt.Sprintf("connected: %d, family: %d, prefix: %s", n.Connected, n.Family, n.Prefix.String())
+ return fmt.Sprintf(
+ "connected: %d, family: %d, prefix: %s",
+ n.Connected, n.Family, n.Prefix.String())
}
type NexthopRegisterBody struct {
@@ -1461,6 +1721,7 @@ type NexthopUpdateBody struct {
// - 32 if Address Family is AF_INET
// - 128 if Address Family is AF_INET6
Prefix net.IP
+ Distance uint8
Metric uint32
Nexthops []*Nexthop
}
@@ -1504,9 +1765,16 @@ func (b *NexthopUpdateBody) DecodeFromBytes(data []byte, version uint8) error {
}
offset += addrLen
+ // Distance (1 byte) (if version>=4)
// Metric (4 bytes)
// Number of Nexthops (1 byte)
- if len(data[offset:]) < 4+1 {
+ if version >= 4 {
+ if len(data[offset:]) < 6 {
+ return fmt.Errorf("invalid message length: missing distance(1 byte), metric(4 bytes) or nexthops(1 byte): %d<6", len(data[offset:]))
+ }
+ b.Distance = data[offset]
+ offset += 1
+ } else if len(data[offset:]) < 5 {
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])
@@ -1514,7 +1782,7 @@ func (b *NexthopUpdateBody) DecodeFromBytes(data []byte, version uint8) error {
// List of Nexthops
b.Nexthops = []*Nexthop{}
- if nexthopsByteLen, err := decodeNexthopsFromBytes(&b.Nexthops, data[offset:], isV4); err != nil {
+ if nexthopsByteLen, err := decodeNexthopsFromBytes(&b.Nexthops, data[offset:], isV4, version); err != nil {
return err
} else {
offset += nexthopsByteLen
@@ -1524,7 +1792,9 @@ func (b *NexthopUpdateBody) DecodeFromBytes(data []byte, version uint8) error {
}
func (b *NexthopUpdateBody) String() string {
- s := fmt.Sprintf("family: %d, prefix: %s, metric: %d", b.Family, b.Prefix.String(), b.Metric)
+ s := fmt.Sprintf(
+ "family: %d, prefix: %s, distance: %d, metric: %d",
+ b.Family, b.Prefix.String(), b.Distance, b.Metric)
for _, nh := range b.Nexthops {
s = s + fmt.Sprintf(", nexthop:{%s}", nh.String())
}
@@ -1553,9 +1823,7 @@ func (m *Message) Serialize() ([]byte, error) {
return append(hdr, body...), nil
}
-func ParseMessage(hdr *Header, data []byte) (*Message, error) {
- m := &Message{Header: *hdr}
-
+func (m *Message) parseMessage(data []byte) error {
switch m.Header.Command {
case INTERFACE_ADD, INTERFACE_DELETE, INTERFACE_UP, INTERFACE_DOWN:
m.Body = &InterfaceUpdateBody{}
@@ -1565,31 +1833,64 @@ func ParseMessage(hdr *Header, data []byte) (*Message, error) {
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:
m.Body = &UnknownBody{}
- log.WithFields(log.Fields{
- "Topic": "Zebra",
- }).Debugf("unknown message received: %v", data)
}
- err := m.Body.DecodeFromBytes(data, m.Header.Version)
+ return m.Body.DecodeFromBytes(data, m.Header.Version)
+}
+
+func (m *Message) parseFrrMessage(data []byte) error {
+ switch m.Header.Command {
+ case FRR_INTERFACE_ADD, FRR_INTERFACE_DELETE, FRR_INTERFACE_UP, FRR_INTERFACE_DOWN:
+ m.Body = &InterfaceUpdateBody{}
+ case FRR_INTERFACE_ADDRESS_ADD, FRR_INTERFACE_ADDRESS_DELETE:
+ m.Body = &InterfaceAddressUpdateBody{}
+ case FRR_ROUTER_ID_UPDATE:
+ m.Body = &RouterIDUpdateBody{}
+ case FRR_NEXTHOP_UPDATE:
+ m.Body = &NexthopUpdateBody{}
+ case FRR_INTERFACE_NBR_ADDRESS_ADD, FRR_INTERFACE_NBR_ADDRESS_DELETE:
+ // TODO
+ m.Body = &UnknownBody{}
+ case FRR_INTERFACE_BFD_DEST_UPDATE:
+ // TODO
+ m.Body = &UnknownBody{}
+ case FRR_IMPORT_CHECK_UPDATE:
+ // TODO
+ m.Body = &UnknownBody{}
+ case FRR_BFD_DEST_REPLAY:
+ // TODO
+ m.Body = &UnknownBody{}
+ case FRR_REDISTRIBUTE_IPV4_ADD, FRR_REDISTRIBUTE_IPV4_DEL, FRR_REDISTRIBUTE_IPV6_ADD, FRR_REDISTRIBUTE_IPV6_DEL:
+ m.Body = &IPRouteBody{Api: m.Header.Command}
+ case FRR_INTERFACE_VRF_UPDATE:
+ // TODO
+ m.Body = &UnknownBody{}
+ case FRR_INTERFACE_LINK_PARAMS:
+ // TODO
+ m.Body = &UnknownBody{}
+ case FRR_PW_STATUS_UPDATE:
+ // TODO
+ m.Body = &UnknownBody{}
+ default:
+ m.Body = &UnknownBody{}
+ }
+ return m.Body.DecodeFromBytes(data, m.Header.Version)
+}
+
+func ParseMessage(hdr *Header, data []byte) (m *Message, err error) {
+ m = &Message{Header: *hdr}
+ if m.Header.Version == 4 {
+ err = m.parseFrrMessage(data)
+ } else {
+ err = m.parseMessage(data)
+ }
if err != nil {
return nil, err
}