Skip to content
Snippets Groups Projects
mp_reach_nlri.go 2.14 KiB
Newer Older
  • Learn to ignore specific revisions
  • Daniel Czerwonk's avatar
    Daniel Czerwonk committed
    package packet
    
    import (
    	"bytes"
    
    Daniel Czerwonk's avatar
    Daniel Czerwonk committed
    
    	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)
    
    Daniel Czerwonk's avatar
    Daniel Czerwonk committed
    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 {
    
    Daniel Czerwonk's avatar
    Daniel Czerwonk committed
    	nextHop := n.NextHop.Bytes()
    
    	tempBuf := bytes.NewBuffer(nil)
    	tempBuf.Write(convert.Uint16Byte(n.AFI))
    	tempBuf.WriteByte(n.SAFI)
    
    	tempBuf.WriteByte(uint8(len(nextHop)))
    
    Daniel Czerwonk's avatar
    Daniel Czerwonk committed
    	tempBuf.Write(nextHop)
    	tempBuf.WriteByte(0) // RESERVED
    
    Daniel Czerwonk's avatar
    Daniel Czerwonk committed
    
    	for cur := n.NLRI; cur != nil; cur = cur.Next {
    
    		if opt.UseAddPath {
    
    Daniel Czerwonk's avatar
    Daniel Czerwonk committed
    			n.NLRI.serializeAddPath(tempBuf)
    		} else {
    			n.NLRI.serialize(tempBuf)
    
    Daniel Czerwonk's avatar
    Daniel Czerwonk committed
    
    	buf.Write(tempBuf.Bytes())
    
    
    Daniel Czerwonk's avatar
    Daniel Czerwonk committed
    	return uint16(tempBuf.Len())
    
    
    func deserializeMultiProtocolReachNLRI(b []byte) (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)
    	if err != nil {
    		return MultiProtocolReachNLRI{}, err
    
    Daniel Czerwonk's avatar
    Daniel Czerwonk committed
    	n.NLRI = nlri