mirror of
https://github.com/osrg/gobgp.git
synced 2024-05-11 05:55:10 +00:00
Add MRT-specific MP_REACH_NLRI encoding
This form, as defined in RFC 6396 4.3.4, is found in many public MRT dumps.
This commit is contained in:
committed by
FUJITA Tomonori
parent
78e9380375
commit
c801e18495
+69
-21
@@ -32,8 +32,21 @@ import (
|
||||
)
|
||||
|
||||
type MarshallingOption struct {
|
||||
AddPath map[RouteFamily]BGPAddPathMode
|
||||
Attributes map[BGPAttrType]bool
|
||||
AddPath map[RouteFamily]BGPAddPathMode
|
||||
Attributes map[BGPAttrType]bool
|
||||
ImplicitPrefix AddrPrefixInterface
|
||||
}
|
||||
|
||||
// GetImplicitPrefix gets the implicit prefix associated with decoding/serialisation. This is used for
|
||||
// the MRT representation of MP_REACH_NLRI (see RFC 6396 4.3.4).
|
||||
func GetImplicitPrefix(options []*MarshallingOption) AddrPrefixInterface {
|
||||
for _, opt := range options {
|
||||
if opt != nil && opt.ImplicitPrefix != nil {
|
||||
return opt.ImplicitPrefix
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func IsAddPathEnabled(decode bool, f RouteFamily, options []*MarshallingOption) bool {
|
||||
@@ -10952,19 +10965,35 @@ func (p *PathAttributeMpReachNLRI) DecodeFromBytes(data []byte, options ...*Mars
|
||||
if p.Length < 3 {
|
||||
return NewMessageError(eCode, eSubCode, value, "mpreach header length is short")
|
||||
}
|
||||
afi := binary.BigEndian.Uint16(value[0:2])
|
||||
safi := value[2]
|
||||
|
||||
var afi uint16
|
||||
var safi uint8
|
||||
|
||||
// In MRT dumps, AFI+SAFI+NLRI is implicit based on RIB Entry Header, see RFC 6396 4.3.4
|
||||
implicitPrefix := GetImplicitPrefix(options)
|
||||
if implicitPrefix == nil {
|
||||
afi = binary.BigEndian.Uint16(value[0:2])
|
||||
safi = value[2]
|
||||
|
||||
value = value[3:]
|
||||
} else {
|
||||
afi = implicitPrefix.AFI()
|
||||
safi = implicitPrefix.SAFI()
|
||||
|
||||
p.Value = []AddrPrefixInterface{implicitPrefix}
|
||||
}
|
||||
|
||||
p.AFI = afi
|
||||
p.SAFI = safi
|
||||
_, err = NewPrefixFromRouteFamily(afi, safi)
|
||||
if err != nil {
|
||||
return NewMessageError(eCode, BGP_ERROR_SUB_INVALID_NETWORK_FIELD, eData, err.Error())
|
||||
}
|
||||
nexthoplen := int(value[3])
|
||||
if len(value) < 4+nexthoplen {
|
||||
nexthoplen := int(value[0])
|
||||
if len(value) < 1+nexthoplen {
|
||||
return NewMessageError(eCode, eSubCode, value, "mpreach nexthop length is short")
|
||||
}
|
||||
nexthopbin := value[4 : 4+nexthoplen]
|
||||
nexthopbin := value[1 : 1+nexthoplen]
|
||||
if nexthoplen > 0 {
|
||||
v4addrlen := 4
|
||||
v6addrlen := 16
|
||||
@@ -10984,7 +11013,13 @@ func (p *PathAttributeMpReachNLRI) DecodeFromBytes(data []byte, options ...*Mars
|
||||
return NewMessageError(eCode, eSubCode, value, "mpreach nexthop length is incorrect")
|
||||
}
|
||||
}
|
||||
value = value[4+nexthoplen:]
|
||||
|
||||
// NLRI implicit for MRT dumps
|
||||
if implicitPrefix != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
value = value[1+nexthoplen:]
|
||||
// skip reserved
|
||||
if len(value) == 0 {
|
||||
return NewMessageError(eCode, eSubCode, value, "no skip byte")
|
||||
@@ -11030,27 +11065,40 @@ func (p *PathAttributeMpReachNLRI) Serialize(options ...*MarshallingOption) ([]b
|
||||
if p.LinkLocalNexthop != nil && p.LinkLocalNexthop.IsLinkLocalUnicast() {
|
||||
nexthoplen = BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
|
||||
}
|
||||
buf := make([]byte, 4+nexthoplen)
|
||||
binary.BigEndian.PutUint16(buf[0:], afi)
|
||||
buf[2] = safi
|
||||
buf[3] = uint8(nexthoplen)
|
||||
var buf []byte
|
||||
includeNLRI := GetImplicitPrefix(options) == nil
|
||||
if includeNLRI {
|
||||
family := make([]byte, 3)
|
||||
binary.BigEndian.PutUint16(family[0:], afi)
|
||||
family[2] = safi
|
||||
|
||||
buf = append(buf, family...)
|
||||
}
|
||||
buf = append(buf, uint8(nexthoplen))
|
||||
if nexthoplen != 0 {
|
||||
nexthop := make([]byte, nexthoplen)
|
||||
|
||||
if p.Nexthop.To4() == nil {
|
||||
copy(buf[4+offset:], p.Nexthop.To16())
|
||||
copy(nexthop[offset:], p.Nexthop.To16())
|
||||
|
||||
if nexthoplen == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL {
|
||||
copy(buf[4+offset+16:], p.LinkLocalNexthop.To16())
|
||||
copy(nexthop[offset+16:], p.LinkLocalNexthop.To16())
|
||||
}
|
||||
} else {
|
||||
copy(buf[4+offset:], p.Nexthop)
|
||||
copy(nexthop[offset:], p.Nexthop)
|
||||
}
|
||||
|
||||
buf = append(buf, nexthop...)
|
||||
}
|
||||
buf = append(buf, 0)
|
||||
for _, prefix := range p.Value {
|
||||
pbuf, err := prefix.Serialize(options...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if includeNLRI {
|
||||
buf = append(buf, 0)
|
||||
for _, prefix := range p.Value {
|
||||
pbuf, err := prefix.Serialize(options...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buf = append(buf, pbuf...)
|
||||
}
|
||||
buf = append(buf, pbuf...)
|
||||
}
|
||||
return p.PathAttribute.Serialize(buf, options...)
|
||||
}
|
||||
|
||||
@@ -1105,6 +1105,38 @@ func Test_MpReachNLRIWithIPv4PrefixWithIPv6Nexthop(t *testing.T) {
|
||||
assert.Equal(bufin, bufout)
|
||||
}
|
||||
|
||||
func Test_MpReachNLRIWithImplicitPrefix(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
bufin := []byte{
|
||||
0x80, 0x0e, 0x11, // flags(1), type(1), length(1)
|
||||
0x10, // nexthoplen(1)
|
||||
0x20, 0x01, 0x0d, 0xb8, // nexthop(32)
|
||||
0x00, 0x01, 0x00, 0x00, // = "2001:db8:1::1"
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x01,
|
||||
}
|
||||
prefix := NewIPAddrPrefix(24, "192.168.10.0")
|
||||
// Test DecodeFromBytes()
|
||||
p := &PathAttributeMpReachNLRI{}
|
||||
option := &MarshallingOption{ImplicitPrefix: prefix}
|
||||
err := p.DecodeFromBytes(bufin, option)
|
||||
assert.Nil(err)
|
||||
// Test decoded values
|
||||
assert.Equal(BGPAttrFlag(0x80), p.Flags)
|
||||
assert.Equal(BGPAttrType(0xe), p.Type)
|
||||
assert.Equal(uint16(0x11), p.Length)
|
||||
assert.Equal(prefix.AFI(), p.AFI)
|
||||
assert.Equal(prefix.SAFI(), p.SAFI)
|
||||
assert.Equal(net.ParseIP("2001:db8:1::1"), p.Nexthop)
|
||||
value := []AddrPrefixInterface{prefix}
|
||||
assert.Equal(value, p.Value)
|
||||
// Test Serialize()
|
||||
bufout, err := p.Serialize(option)
|
||||
assert.Nil(err)
|
||||
// Test serialised value
|
||||
assert.Equal(bufin, bufout)
|
||||
}
|
||||
|
||||
func Test_ParseRouteDistinguisher(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
|
||||
+6
-16
@@ -365,7 +365,7 @@ type RibEntry struct {
|
||||
|
||||
var errNotAllRibEntryBytesAvailable = errors.New("not all RibEntry bytes are available")
|
||||
|
||||
func (e *RibEntry) DecodeFromBytes(data []byte) ([]byte, error) {
|
||||
func (e *RibEntry) DecodeFromBytes(data []byte, prefix bgp.AddrPrefixInterface) ([]byte, error) {
|
||||
if len(data) < 8 {
|
||||
return nil, errNotAllRibEntryBytesAvailable
|
||||
}
|
||||
@@ -384,7 +384,7 @@ func (e *RibEntry) DecodeFromBytes(data []byte) ([]byte, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = p.DecodeFromBytes(data)
|
||||
err = p.DecodeFromBytes(data, &bgp.MarshallingOption{ImplicitPrefix: prefix})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -398,21 +398,11 @@ func (e *RibEntry) DecodeFromBytes(data []byte) ([]byte, error) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (e *RibEntry) Serialize() ([]byte, error) {
|
||||
func (e *RibEntry) Serialize(prefix bgp.AddrPrefixInterface) ([]byte, error) {
|
||||
pbuf := make([]byte, 0)
|
||||
totalLen := 0
|
||||
for _, pattr := range e.PathAttributes {
|
||||
// TODO special modification is needed for MP_REACH_NLRI
|
||||
// but also Quagga doesn't implement this.
|
||||
//
|
||||
// RFC 6396 4.3.4
|
||||
// There is one exception to the encoding of BGP attributes for the BGP
|
||||
// MP_REACH_NLRI attribute (BGP Type Code 14).
|
||||
// Since the AFI, SAFI, and NLRI information is already encoded
|
||||
// in the RIB Entry Header or RIB_GENERIC Entry Header,
|
||||
// only the Next Hop Address Length and Next Hop Address fields are included.
|
||||
|
||||
pb, err := pattr.Serialize()
|
||||
pb, err := pattr.Serialize(&bgp.MarshallingOption{ImplicitPrefix: prefix})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -492,7 +482,7 @@ func (u *Rib) DecodeFromBytes(data []byte) error {
|
||||
e := &RibEntry{
|
||||
isAddPath: u.isAddPath,
|
||||
}
|
||||
data, err = e.DecodeFromBytes(data)
|
||||
data, err = e.DecodeFromBytes(data, prefix)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -524,7 +514,7 @@ func (u *Rib) Serialize() ([]byte, error) {
|
||||
}
|
||||
buf = append(buf, bbuf...)
|
||||
for _, entry := range u.Entries {
|
||||
bbuf, err = entry.Serialize()
|
||||
bbuf, err = entry.Serialize(u.Prefix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -116,13 +116,13 @@ func TestMrtRibEntry(t *testing.T) {
|
||||
}
|
||||
|
||||
e1 := NewRibEntry(1, uint32(time.Now().Unix()), 0, p, false)
|
||||
b1, err := e1.Serialize()
|
||||
b1, err := e1.Serialize(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
e2 := &RibEntry{}
|
||||
rest, err := e2.DecodeFromBytes(b1)
|
||||
rest, err := e2.DecodeFromBytes(b1, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -145,13 +145,13 @@ func TestMrtRibEntryWithAddPath(t *testing.T) {
|
||||
bgp.NewPathAttributeLocalPref(1 << 22),
|
||||
}
|
||||
e1 := NewRibEntry(1, uint32(time.Now().Unix()), 200, p, true)
|
||||
b1, err := e1.Serialize()
|
||||
b1, err := e1.Serialize(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
e2 := &RibEntry{isAddPath: true}
|
||||
rest, err := e2.DecodeFromBytes(b1)
|
||||
rest, err := e2.DecodeFromBytes(b1, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user