Skip to content
Snippets Groups Projects
mp_reach_nlri.go 2.11 KiB
Newer Older
package packet

import (
	"bytes"

	bnet "github.com/bio-routing/bio-rd/net"
	"github.com/bio-routing/bio-rd/util/decode"
Daniel Czerwonk's avatar
Daniel Czerwonk committed
	"github.com/taktv6/tflow2/convert"
Daniel Czerwonk's avatar
Daniel Czerwonk committed
// MultiProtocolReachNLRI represents network layer reachability information for an IP address family (rfc4760)
type MultiProtocolReachNLRI struct {
Daniel Czerwonk's avatar
Daniel Czerwonk committed
	AFI     uint16
	SAFI    uint8
	NextHop bnet.IP
	NLRI    *NLRI
func (n *MultiProtocolReachNLRI) serialize(buf *bytes.Buffer, opt *EncodeOptions) uint16 {
	nextHop := n.NextHop.Bytes()

	tempBuf := bytes.NewBuffer(nil)
	tempBuf.Write(convert.Uint16Byte(n.AFI))
	tempBuf.WriteByte(n.SAFI)
	tempBuf.WriteByte(uint8(len(nextHop)))
	tempBuf.Write(nextHop)
	tempBuf.WriteByte(0) // RESERVED
Daniel Czerwonk's avatar
Daniel Czerwonk committed

	for cur := n.NLRI; cur != nil; cur = cur.Next {
		cur.serialize(tempBuf, opt.UseAddPath)

	buf.Write(tempBuf.Bytes())

Daniel Czerwonk's avatar
Daniel Czerwonk committed
	return uint16(tempBuf.Len())
func deserializeMultiProtocolReachNLRI(b []byte, addPath bool) (MultiProtocolReachNLRI, error) {
	n := MultiProtocolReachNLRI{}
	nextHopLength := uint8(0)

Daniel Czerwonk's avatar
Daniel Czerwonk committed
	variableLength := len(b) - 4 // 4 <- AFI + SAFI + NextHopLength
	if variableLength <= 0 {
		return n, fmt.Errorf("Invalid length of MP_REACH_NLRI: expected more than 4 bytes but got %d", len(b))
	}

	variable := make([]byte, variableLength)
	fields := []interface{}{
		&n.AFI,
		&n.SAFI,
		&nextHopLength,
		&variable,
	}
	err := decode.Decode(bytes.NewBuffer(b), fields)
	if err != nil {
		return MultiProtocolReachNLRI{}, err
	}

Daniel Czerwonk's avatar
Daniel Czerwonk committed
	budget := variableLength
	if budget < int(nextHopLength) {
		return MultiProtocolReachNLRI{},
			fmt.Errorf("Failed to decode next hop IP: expected %d bytes for NLRI, only %d remaining", nextHopLength, budget)
	}

	n.NextHop, err = bnet.IPFromBytes(variable[:nextHopLength])
	if err != nil {
		return MultiProtocolReachNLRI{}, fmt.Errorf("Failed to decode next hop IP: %v", err)
	}
Daniel Czerwonk's avatar
Daniel Czerwonk committed
	budget -= int(nextHopLength)
Daniel Czerwonk's avatar
Daniel Czerwonk committed
	if budget == 0 {
Daniel Czerwonk's avatar
Daniel Czerwonk committed
		return n, nil
	}

Daniel Czerwonk's avatar
Daniel Czerwonk committed
	variable = variable[1+nextHopLength:] // 1 <- RESERVED field

Daniel Czerwonk's avatar
Daniel Czerwonk committed
	buf := bytes.NewBuffer(variable)
	nlri, err := decodeNLRIs(buf, uint16(buf.Len()), n.AFI, addPath)
Daniel Czerwonk's avatar
Daniel Czerwonk committed
	if err != nil {
		return MultiProtocolReachNLRI{}, err
Daniel Czerwonk's avatar
Daniel Czerwonk committed
	n.NLRI = nlri