summaryrefslogtreecommitdiffhomepage
path: root/packet/bgp
diff options
context:
space:
mode:
Diffstat (limited to 'packet/bgp')
-rw-r--r--packet/bgp/bgp.go353
-rw-r--r--packet/bgp/bgp_test.go144
-rw-r--r--packet/bgp/validate_test.go2
3 files changed, 445 insertions, 54 deletions
diff --git a/packet/bgp/bgp.go b/packet/bgp/bgp.go
index bdab5da1..91a6b05f 100644
--- a/packet/bgp/bgp.go
+++ b/packet/bgp/bgp.go
@@ -28,7 +28,25 @@ import (
"strings"
)
-type MarshallingOption struct{}
+type MarshallingOption struct {
+ AddPath map[RouteFamily]BGPAddPathMode
+}
+
+func handleAddPath(decode bool, f RouteFamily, options []*MarshallingOption) bool {
+ for _, opt := range options {
+ if opt == nil {
+ continue
+ }
+ if o := opt.AddPath; o != nil {
+ if decode && o[f]&BGP_ADD_PATH_RECEIVE > 0 {
+ return true
+ } else if !decode && o[f]&BGP_ADD_PATH_SEND > 0 {
+ return true
+ }
+ }
+ }
+ return false
+}
const (
AFI_IP = 1
@@ -574,13 +592,16 @@ func NewCapFourOctetASNumber(asnum uint32) *CapFourOctetASNumber {
type BGPAddPathMode uint8
const (
- BGP_ADD_PATH_RECEIVE BGPAddPathMode = 1
- BGP_ADD_PATH_SEND BGPAddPathMode = 2
- BGP_ADD_PATH_BOTH BGPAddPathMode = 3
+ BGP_ADD_PATH_NONE BGPAddPathMode = iota
+ BGP_ADD_PATH_RECEIVE
+ BGP_ADD_PATH_SEND
+ BGP_ADD_PATH_BOTH
)
func (m BGPAddPathMode) String() string {
switch m {
+ case BGP_ADD_PATH_NONE:
+ return "none"
case BGP_ADD_PATH_RECEIVE:
return "receive"
case BGP_ADD_PATH_SEND:
@@ -968,13 +989,43 @@ type AddrPrefixInterface interface {
Len(...*MarshallingOption) int
String() string
MarshalJSON() ([]byte, error)
-
// Create a flat map to describe attributes and their
// values. This can be used to create structured outputs.
Flat() map[string]string
+ PathIdentifier() uint32
+ SetPathIdentifier(uint32)
+}
+
+type PrefixDefault struct {
+ id uint32
+}
+
+func (p *PrefixDefault) PathIdentifier() uint32 {
+ return p.id
+}
+
+func (p *PrefixDefault) SetPathIdentifier(id uint32) {
+ p.id = id
+}
+
+func (p *PrefixDefault) decodePathIdentifier(data []byte) ([]byte, error) {
+ if len(data) < 4 {
+ code := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
+ subcode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST)
+ return nil, NewMessageError(code, subcode, nil, "prefix misses path identifier field")
+ }
+ p.SetPathIdentifier(binary.BigEndian.Uint32(data[:4]))
+ return data[4:], nil
+}
+
+func (p *PrefixDefault) serializeIdentifier() ([]byte, error) {
+ buf := make([]byte, 4)
+ binary.BigEndian.PutUint32(buf, p.PathIdentifier())
+ return buf, nil
}
type IPAddrPrefixDefault struct {
+ PrefixDefault
Length uint8
Prefix net.IP
}
@@ -1031,21 +1082,43 @@ type IPAddrPrefix struct {
}
func (r *IPAddrPrefix) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
+ if r.addrlen == 0 {
+ r.addrlen = 4
+ }
+ f := RF_IPv4_UC
+ if r.addrlen == 16 {
+ f = RF_IPv6_UC
+ }
+ if handleAddPath(true, f, options) {
+ var err error
+ data, err = r.decodePathIdentifier(data)
+ if err != nil {
+ return err
+ }
+ }
if len(data) < 1 {
eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST)
return NewMessageError(eCode, eSubCode, nil, "prefix misses length field")
}
r.Length = data[0]
- if r.addrlen == 0 {
- r.addrlen = 4
- }
return r.decodePrefix(data[1:], r.Length, r.addrlen)
}
func (r *IPAddrPrefix) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := make([]byte, 1)
- buf[0] = r.Length
+ f := RF_IPv4_UC
+ if r.addrlen == 16 {
+ f = RF_IPv6_UC
+ }
+ var buf []byte
+ if handleAddPath(false, f, options) {
+ var err error
+ buf, err = r.serializeIdentifier()
+ if err != nil {
+ return nil, err
+ }
+ }
+ buf = append(buf, r.Length)
pbuf, err := r.serializePrefix(r.Length)
if err != nil {
return nil, err
@@ -1063,7 +1136,10 @@ func (r *IPAddrPrefix) SAFI() uint8 {
func NewIPAddrPrefix(length uint8, prefix string) *IPAddrPrefix {
return &IPAddrPrefix{
- IPAddrPrefixDefault{length, net.ParseIP(prefix).To4()},
+ IPAddrPrefixDefault{
+ Length: length,
+ Prefix: net.ParseIP(prefix).To4(),
+ },
4,
}
}
@@ -1091,7 +1167,10 @@ func (r *IPv6AddrPrefix) String() string {
func NewIPv6AddrPrefix(length uint8, prefix string) *IPv6AddrPrefix {
return &IPv6AddrPrefix{
IPAddrPrefix{
- IPAddrPrefixDefault{length, net.ParseIP(prefix)},
+ IPAddrPrefixDefault{
+ Length: length,
+ Prefix: net.ParseIP(prefix),
+ },
16,
},
}
@@ -1468,6 +1547,20 @@ type LabeledVPNIPAddrPrefix struct {
}
func (l *LabeledVPNIPAddrPrefix) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
+ f := RF_IPv4_VPN
+ if l.addrlen == 16 {
+ f = RF_IPv6_VPN
+ }
+ if handleAddPath(true, f, options) {
+ var err error
+ data, err = l.decodePathIdentifier(data)
+ if err != nil {
+ return err
+ }
+ }
+ if len(data) < 1 {
+ return NewMessageError(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST), nil, "prefix misses length field")
+ }
l.Length = uint8(data[0])
data = data[1:]
l.Labels.DecodeFromBytes(data)
@@ -1478,13 +1571,23 @@ func (l *LabeledVPNIPAddrPrefix) DecodeFromBytes(data []byte, options ...*Marsha
l.RD = GetRouteDistinguisher(data)
data = data[l.RD.Len():]
restbits := int(l.Length) - 8*(l.Labels.Len()+l.RD.Len())
- l.decodePrefix(data, uint8(restbits), l.addrlen)
- return nil
+ return l.decodePrefix(data, uint8(restbits), l.addrlen)
}
func (l *LabeledVPNIPAddrPrefix) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := make([]byte, 1)
- buf[0] = l.Length
+ f := RF_IPv4_VPN
+ if l.addrlen == 16 {
+ f = RF_IPv6_VPN
+ }
+ var buf []byte
+ if handleAddPath(false, f, options) {
+ var err error
+ buf, err = l.serializeIdentifier()
+ if err != nil {
+ return nil, err
+ }
+ }
+ buf = append(buf, l.Length)
lbuf, err := l.Labels.Serialize()
if err != nil {
return nil, err
@@ -1540,7 +1643,10 @@ func NewLabeledVPNIPAddrPrefix(length uint8, prefix string, label MPLSLabelStack
rdlen = rd.Len()
}
return &LabeledVPNIPAddrPrefix{
- IPAddrPrefixDefault{length + uint8(8*(label.Len()+rdlen)), net.ParseIP(prefix).To4()},
+ IPAddrPrefixDefault{
+ Length: length + uint8(8*(label.Len()+rdlen)),
+ Prefix: net.ParseIP(prefix).To4(),
+ },
label,
rd,
4,
@@ -1562,7 +1668,10 @@ func NewLabeledVPNIPv6AddrPrefix(length uint8, prefix string, label MPLSLabelSta
}
return &LabeledVPNIPv6AddrPrefix{
LabeledVPNIPAddrPrefix{
- IPAddrPrefixDefault{length + uint8(8*(label.Len()+rdlen)), net.ParseIP(prefix)},
+ IPAddrPrefixDefault{
+ Length: length + uint8(8*(label.Len()+rdlen)),
+ Prefix: net.ParseIP(prefix),
+ },
label,
rd,
16,
@@ -1585,6 +1694,17 @@ func (r *LabeledIPAddrPrefix) SAFI() uint8 {
}
func (l *LabeledIPAddrPrefix) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
+ f := RF_IPv4_MPLS
+ if l.addrlen == 16 {
+ f = RF_IPv6_MPLS
+ }
+ if handleAddPath(true, f, options) {
+ var err error
+ data, err = l.decodePathIdentifier(data)
+ if err != nil {
+ return err
+ }
+ }
l.Length = uint8(data[0])
data = data[1:]
l.Labels.DecodeFromBytes(data)
@@ -1598,8 +1718,19 @@ func (l *LabeledIPAddrPrefix) DecodeFromBytes(data []byte, options ...*Marshalli
}
func (l *LabeledIPAddrPrefix) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := make([]byte, 1)
- buf[0] = l.Length
+ f := RF_IPv4_MPLS
+ if l.addrlen == 16 {
+ f = RF_IPv6_MPLS
+ }
+ var buf []byte
+ if handleAddPath(false, f, options) {
+ var err error
+ buf, err = l.serializeIdentifier()
+ if err != nil {
+ return nil, err
+ }
+ }
+ buf = append(buf, l.Length)
restbits := int(l.Length) - 8*(l.Labels.Len())
lbuf, err := l.Labels.Serialize()
if err != nil {
@@ -1634,7 +1765,10 @@ func (l *LabeledIPAddrPrefix) MarshalJSON() ([]byte, error) {
func NewLabeledIPAddrPrefix(length uint8, prefix string, label MPLSLabelStack) *LabeledIPAddrPrefix {
return &LabeledIPAddrPrefix{
- IPAddrPrefixDefault{length + uint8(label.Len()*8), net.ParseIP(prefix).To4()},
+ IPAddrPrefixDefault{
+ Length: length + uint8(label.Len()*8),
+ Prefix: net.ParseIP(prefix).To4(),
+ },
label,
4,
}
@@ -1651,7 +1785,10 @@ func (l *LabeledIPv6AddrPrefix) AFI() uint16 {
func NewLabeledIPv6AddrPrefix(length uint8, prefix string, label MPLSLabelStack) *LabeledIPv6AddrPrefix {
return &LabeledIPv6AddrPrefix{
LabeledIPAddrPrefix{
- IPAddrPrefixDefault{length + uint8(label.Len()*8), net.ParseIP(prefix)},
+ IPAddrPrefixDefault{
+ Length: length + uint8(label.Len()*8),
+ Prefix: net.ParseIP(prefix),
+ },
label,
16,
},
@@ -1659,12 +1796,23 @@ func NewLabeledIPv6AddrPrefix(length uint8, prefix string, label MPLSLabelStack)
}
type RouteTargetMembershipNLRI struct {
+ PrefixDefault
Length uint8
AS uint32
RouteTarget ExtendedCommunityInterface
}
func (n *RouteTargetMembershipNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
+ if handleAddPath(true, RF_RTC_UC, options) {
+ var err error
+ data, err = n.decodePathIdentifier(data)
+ if err != nil {
+ return err
+ }
+ }
+ if len(data) < 1 {
+ return NewMessageError(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST), nil, "prefix misses length field")
+ }
n.Length = data[0]
data = data[1:]
if len(data) == 0 {
@@ -1682,18 +1830,26 @@ func (n *RouteTargetMembershipNLRI) DecodeFromBytes(data []byte, options ...*Mar
}
func (n *RouteTargetMembershipNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) {
+ var buf []byte
+ if handleAddPath(false, RF_RTC_UC, options) {
+ var err error
+ buf, err = n.serializeIdentifier()
+ if err != nil {
+ return nil, err
+ }
+ }
if n.RouteTarget == nil {
- return []byte{0}, nil
+ return append(buf, 0), nil
}
- buf := make([]byte, 5)
- buf[0] = 12 * 8
- binary.BigEndian.PutUint32(buf[1:], n.AS)
+ offset := len(buf)
+ buf = append(buf, make([]byte, 5)...)
+ buf[offset] = 12 * 8
+ binary.BigEndian.PutUint32(buf[offset+1:], n.AS)
ebuf, err := n.RouteTarget.Serialize()
if err != nil {
return nil, err
}
- buf = append(buf, ebuf...)
- return buf, nil
+ return append(buf, ebuf...), nil
}
func (n *RouteTargetMembershipNLRI) AFI() uint16 {
@@ -2311,12 +2467,20 @@ const (
)
type EVPNNLRI struct {
+ PrefixDefault
RouteType uint8
Length uint8
RouteTypeData EVPNRouteTypeInterface
}
func (n *EVPNNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
+ if handleAddPath(true, RF_EVPN, options) {
+ var err error
+ data, err = n.decodePathIdentifier(data)
+ if err != nil {
+ return err
+ }
+ }
if len(data) < 2 {
return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all EVPNNLRI bytes available")
}
@@ -2335,16 +2499,24 @@ func (n *EVPNNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption) e
}
func (n *EVPNNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := make([]byte, 2)
- buf[0] = n.RouteType
+ var buf []byte
+ if handleAddPath(false, RF_EVPN, options) {
+ var err error
+ buf, err = n.serializeIdentifier()
+ if err != nil {
+ return nil, err
+ }
+ }
+ offset := len(buf)
+ buf = append(buf, make([]byte, 2)...)
+ buf[offset] = n.RouteType
tbuf, err := n.RouteTypeData.Serialize()
n.Length = uint8(len(tbuf))
- buf[1] = n.Length
+ buf[offset+1] = n.Length
if err != nil {
return nil, err
}
- buf = append(buf, tbuf...)
- return buf, nil
+ return append(buf, tbuf...), nil
}
func (n *EVPNNLRI) AFI() uint16 {
@@ -2382,9 +2554,9 @@ func (n *EVPNNLRI) RD() RouteDistinguisherInterface {
func NewEVPNNLRI(routetype uint8, length uint8, routetypedata EVPNRouteTypeInterface) *EVPNNLRI {
return &EVPNNLRI{
- routetype,
- length,
- routetypedata,
+ RouteType: routetype,
+ Length: length,
+ RouteTypeData: routetypedata,
}
}
@@ -2394,6 +2566,20 @@ type EncapNLRI struct {
}
func (n *EncapNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
+ if n.addrlen == 0 {
+ n.addrlen = 4
+ }
+ f := RF_IPv4_ENCAP
+ if n.addrlen == 16 {
+ f = RF_IPv6_ENCAP
+ }
+ if handleAddPath(true, f, options) {
+ var err error
+ data, err = n.decodePathIdentifier(data)
+ if err != nil {
+ return err
+ }
+ }
if len(data) < 4 {
eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST)
@@ -2407,8 +2593,25 @@ func (n *EncapNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption)
}
func (n *EncapNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := make([]byte, 1)
- buf[0] = n.Length
+ var buf []byte
+ f := RF_IPv4_ENCAP
+ if n.addrlen == 16 {
+ f = RF_IPv6_ENCAP
+ }
+ if handleAddPath(false, f, options) {
+ var err error
+ buf, err = n.serializeIdentifier()
+ if err != nil {
+ return nil, err
+ }
+ }
+ if n.Prefix.To4() != nil {
+ buf = append(buf, net.IPv4len*8)
+ n.Prefix = n.Prefix.To4()
+ } else {
+ buf = append(buf, net.IPv6len*8)
+ }
+ n.Length = buf[len(buf)-1]
pbuf, err := n.serializePrefix(n.Length)
if err != nil {
return nil, err
@@ -2430,7 +2633,7 @@ func (n *EncapNLRI) SAFI() uint8 {
func NewEncapNLRI(endpoint string) *EncapNLRI {
return &EncapNLRI{
- IPAddrPrefixDefault{32, net.ParseIP(endpoint).To4()},
+ IPAddrPrefixDefault{Length: 32, Prefix: net.ParseIP(endpoint).To4()},
4,
}
}
@@ -2446,7 +2649,7 @@ func (n *Encapv6NLRI) AFI() uint16 {
func NewEncapv6NLRI(endpoint string) *Encapv6NLRI {
return &Encapv6NLRI{
EncapNLRI{
- IPAddrPrefixDefault{128, net.ParseIP(endpoint)},
+ IPAddrPrefixDefault{Length: 128, Prefix: net.ParseIP(endpoint)},
16,
},
}
@@ -3466,6 +3669,7 @@ func (p *FlowSpecUnknown) MarshalJSON() ([]byte, error) {
}
type FlowSpecNLRI struct {
+ PrefixDefault
Value []FlowSpecComponentInterface
rf RouteFamily
rd RouteDistinguisherInterface
@@ -3486,6 +3690,13 @@ func (n *FlowSpecNLRI) RD() RouteDistinguisherInterface {
}
func (n *FlowSpecNLRI) decodeFromBytes(rf RouteFamily, data []byte, options ...*MarshallingOption) error {
+ if handleAddPath(true, rf, options) {
+ var err error
+ data, err = n.decodePathIdentifier(data)
+ if err != nil {
+ return err
+ }
+ }
var length int
if (data[0]>>4) == 0xf && len(data) > 2 {
length = int(binary.BigEndian.Uint16(data[0:2]))
@@ -3601,6 +3812,13 @@ func (n *FlowSpecNLRI) Serialize(options ...*MarshallingOption) ([]byte, error)
buf = append(b, buf...)
}
+ if handleAddPath(false, n.rf, options) {
+ id, err := n.serializeIdentifier()
+ if err != nil {
+ return nil, err
+ }
+ return append(id, buf...), nil
+ }
return buf, nil
}
@@ -3778,7 +3996,7 @@ func (n *FlowSpecIPv4Unicast) DecodeFromBytes(data []byte, options ...*Marshalli
}
func NewFlowSpecIPv4Unicast(value []FlowSpecComponentInterface) *FlowSpecIPv4Unicast {
- return &FlowSpecIPv4Unicast{FlowSpecNLRI{value, RF_FS_IPv4_UC, nil}}
+ return &FlowSpecIPv4Unicast{FlowSpecNLRI{Value: value, rf: RF_FS_IPv4_UC}}
}
type FlowSpecIPv4VPN struct {
@@ -3790,7 +4008,7 @@ func (n *FlowSpecIPv4VPN) DecodeFromBytes(data []byte, options ...*MarshallingOp
}
func NewFlowSpecIPv4VPN(rd RouteDistinguisherInterface, value []FlowSpecComponentInterface) *FlowSpecIPv4VPN {
- return &FlowSpecIPv4VPN{FlowSpecNLRI{value, RF_FS_IPv4_VPN, rd}}
+ return &FlowSpecIPv4VPN{FlowSpecNLRI{Value: value, rf: RF_FS_IPv4_VPN, rd: rd}}
}
type FlowSpecIPv6Unicast struct {
@@ -3841,6 +4059,7 @@ func NewFlowSpecL2VPN(rd RouteDistinguisherInterface, value []FlowSpecComponentI
}
type OpaqueNLRI struct {
+ PrefixDefault
Length uint16
Key []byte
Value []byte
@@ -3850,6 +4069,13 @@ func (n *OpaqueNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption)
if len(data) < 2 {
return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all OpaqueNLRI bytes available")
}
+ if handleAddPath(true, RF_OPAQUE, options) {
+ var err error
+ data, err = n.decodePathIdentifier(data)
+ if err != nil {
+ return err
+ }
+ }
n.Length = binary.BigEndian.Uint16(data[0:2])
if len(data)-2 < int(n.Length) {
return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all OpaqueNLRI bytes available")
@@ -3866,7 +4092,15 @@ func (n *OpaqueNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) {
buf := make([]byte, 2)
binary.BigEndian.PutUint16(buf, uint16(len(n.Key)))
buf = append(buf, n.Key...)
- return append(buf, n.Value...), nil
+ buf = append(buf, n.Value...)
+ if handleAddPath(false, RF_OPAQUE, options) {
+ id, err := n.serializeIdentifier()
+ if err != nil {
+ return nil, err
+ }
+ return append(id, buf...), nil
+ }
+ return buf, nil
}
func (n *OpaqueNLRI) AFI() uint16 {
@@ -5326,6 +5560,10 @@ func (p *PathAttributeMpReachNLRI) DecodeFromBytes(data []byte, options ...*Mars
return NewMessageError(eCode, eSubCode, value, "no skip byte")
}
value = value[1:]
+ addpathLen := 0
+ if handleAddPath(true, AfiSafiToRouteFamily(afi, safi), options) {
+ addpathLen = 4
+ }
for len(value) > 0 {
prefix, err := NewPrefixFromRouteFamily(afi, safi)
if err != nil {
@@ -5335,10 +5573,10 @@ func (p *PathAttributeMpReachNLRI) DecodeFromBytes(data []byte, options ...*Mars
if err != nil {
return err
}
- if prefix.Len(options...) > len(value) {
+ if prefix.Len(options...)+addpathLen > len(value) {
return NewMessageError(eCode, eSubCode, value, "prefix length is incorrect")
}
- value = value[prefix.Len(options...):]
+ value = value[prefix.Len(options...)+addpathLen:]
p.Value = append(p.Value, prefix)
}
return nil
@@ -5468,6 +5706,10 @@ func (p *PathAttributeMpUnreachNLRI) DecodeFromBytes(data []byte, options ...*Ma
value = value[3:]
p.AFI = afi
p.SAFI = safi
+ addpathLen := 0
+ if handleAddPath(true, AfiSafiToRouteFamily(afi, safi), options) {
+ addpathLen = 4
+ }
for len(value) > 0 {
prefix, err := NewPrefixFromRouteFamily(afi, safi)
if err != nil {
@@ -5477,10 +5719,10 @@ func (p *PathAttributeMpUnreachNLRI) DecodeFromBytes(data []byte, options ...*Ma
if err != nil {
return err
}
- if prefix.Len(options...) > len(value) {
+ if prefix.Len(options...)+addpathLen > len(value) {
return NewMessageError(eCode, eSubCode, data[:p.PathAttribute.Len(options...)], "prefix length is incorrect")
}
- value = value[prefix.Len(options...):]
+ value = value[prefix.Len(options...)+addpathLen:]
p.Value = append(p.Value, prefix)
}
return nil
@@ -7564,6 +7806,11 @@ func (msg *BGPUpdate) DecodeFromBytes(data []byte, options ...*MarshallingOption
return NewMessageError(eCode, eSubCode, nil, "withdrawn route length exceeds message length")
}
+ addpathLen := 0
+ if handleAddPath(true, RF_IPv4_UC, options) {
+ addpathLen = 4
+ }
+
msg.WithdrawnRoutes = make([]*IPAddrPrefix, 0, msg.WithdrawnRoutesLen)
for routelen := msg.WithdrawnRoutesLen; routelen > 0; {
w := &IPAddrPrefix{}
@@ -7571,11 +7818,11 @@ func (msg *BGPUpdate) DecodeFromBytes(data []byte, options ...*MarshallingOption
if err != nil {
return err
}
- routelen -= uint16(w.Len(options...))
- if len(data) < w.Len(options...) {
+ routelen -= uint16(w.Len(options...) + addpathLen)
+ if len(data) < w.Len(options...)+addpathLen {
return NewMessageError(eCode, eSubCode, nil, "Withdrawn route length is short")
}
- data = data[w.Len(options...):]
+ data = data[w.Len(options...)+addpathLen:]
msg.WithdrawnRoutes = append(msg.WithdrawnRoutes, w)
}
@@ -7617,11 +7864,11 @@ func (msg *BGPUpdate) DecodeFromBytes(data []byte, options ...*MarshallingOption
if err != nil {
return err
}
- restlen -= n.Len(options...)
- if len(data) < n.Len(options...) {
+ restlen -= n.Len(options...) + addpathLen
+ if len(data) < n.Len(options...)+addpathLen {
return NewMessageError(eCode, BGP_ERROR_SUB_INVALID_NETWORK_FIELD, nil, "NLRI length is short")
}
- data = data[n.Len(options...):]
+ data = data[n.Len(options...)+addpathLen:]
msg.NLRI = append(msg.NLRI, n)
}
diff --git a/packet/bgp/bgp_test.go b/packet/bgp/bgp_test.go
index 8fedf5fe..998d0568 100644
--- a/packet/bgp/bgp_test.go
+++ b/packet/bgp/bgp_test.go
@@ -553,6 +553,150 @@ func Test_CapExtendedNexthop(t *testing.T) {
t.Error(len(buf2), n2, buf2)
t.Log(bytes.Equal(buf1, buf2))
}
+}
+
+func Test_AddPath(t *testing.T) {
+ assert := assert.New(t)
+ opt := &MarshallingOption{AddPath: map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}}
+ {
+ n1 := NewIPAddrPrefix(24, "10.10.10.0")
+ assert.Equal(n1.PathIdentifier(), uint32(0))
+ n1.SetPathIdentifier(10)
+ assert.Equal(n1.PathIdentifier(), uint32(10))
+ bits, err := n1.Serialize(opt)
+ assert.Nil(err)
+ n2 := &IPAddrPrefix{}
+ err = n2.DecodeFromBytes(bits, opt)
+ assert.Nil(err)
+ assert.Equal(n2.PathIdentifier(), uint32(10))
+ }
+ {
+ n1 := NewIPv6AddrPrefix(64, "2001::")
+ n1.SetPathIdentifier(10)
+ bits, err := n1.Serialize(opt)
+ assert.Nil(err)
+ n2 := NewIPv6AddrPrefix(0, "")
+ err = n2.DecodeFromBytes(bits, opt)
+ assert.Nil(err)
+ assert.Equal(n2.PathIdentifier(), uint32(0))
+ }
+ opt = &MarshallingOption{AddPath: map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH, RF_IPv6_UC: BGP_ADD_PATH_BOTH}}
+ {
+ n1 := NewIPv6AddrPrefix(64, "2001::")
+ n1.SetPathIdentifier(10)
+ bits, err := n1.Serialize(opt)
+ assert.Nil(err)
+ n2 := NewIPv6AddrPrefix(0, "")
+ err = n2.DecodeFromBytes(bits, opt)
+ assert.Nil(err)
+ assert.Equal(n2.PathIdentifier(), uint32(10))
+ }
+ opt = &MarshallingOption{AddPath: map[RouteFamily]BGPAddPathMode{RF_IPv4_VPN: BGP_ADD_PATH_BOTH, RF_IPv6_VPN: BGP_ADD_PATH_BOTH}}
+ {
+ rd, _ := ParseRouteDistinguisher("100:100")
+ labels := NewMPLSLabelStack(100, 200)
+ n1 := NewLabeledVPNIPAddrPrefix(24, "10.10.10.0", *labels, rd)
+ n1.SetPathIdentifier(20)
+ bits, err := n1.Serialize(opt)
+ assert.Nil(err)
+ n2 := NewLabeledVPNIPAddrPrefix(0, "", MPLSLabelStack{}, nil)
+ err = n2.DecodeFromBytes(bits, opt)
+ assert.Nil(err)
+ assert.Equal(n2.PathIdentifier(), uint32(20))
+ }
+ {
+ rd, _ := ParseRouteDistinguisher("100:100")
+ labels := NewMPLSLabelStack(100, 200)
+ n1 := NewLabeledVPNIPv6AddrPrefix(64, "2001::", *labels, rd)
+ n1.SetPathIdentifier(20)
+ bits, err := n1.Serialize(opt)
+ assert.Nil(err)
+ n2 := NewLabeledVPNIPAddrPrefix(0, "", MPLSLabelStack{}, nil)
+ err = n2.DecodeFromBytes(bits, opt)
+ assert.Nil(err)
+ assert.Equal(n2.PathIdentifier(), uint32(20))
+ }
+ opt = &MarshallingOption{AddPath: map[RouteFamily]BGPAddPathMode{RF_IPv4_MPLS: BGP_ADD_PATH_BOTH, RF_IPv6_MPLS: BGP_ADD_PATH_BOTH}}
+ {
+ labels := NewMPLSLabelStack(100, 200)
+ n1 := NewLabeledIPAddrPrefix(24, "10.10.10.0", *labels)
+ n1.SetPathIdentifier(20)
+ bits, err := n1.Serialize(opt)
+ assert.Nil(err)
+ n2 := NewLabeledIPAddrPrefix(0, "", MPLSLabelStack{})
+ err = n2.DecodeFromBytes(bits, opt)
+ assert.Nil(err)
+ assert.Equal(n2.PathIdentifier(), uint32(20))
+ }
+ {
+ labels := NewMPLSLabelStack(100, 200)
+ n1 := NewLabeledIPv6AddrPrefix(64, "2001::", *labels)
+ n1.SetPathIdentifier(20)
+ bits, err := n1.Serialize(opt)
+ assert.Nil(err)
+ n2 := NewLabeledIPAddrPrefix(0, "", MPLSLabelStack{})
+ err = n2.DecodeFromBytes(bits, opt)
+ assert.Nil(err)
+ assert.Equal(n2.PathIdentifier(), uint32(20))
+ }
+ opt = &MarshallingOption{AddPath: map[RouteFamily]BGPAddPathMode{RF_RTC_UC: BGP_ADD_PATH_BOTH}}
+ {
+ rt, _ := ParseRouteTarget("100:100")
+ n1 := NewRouteTargetMembershipNLRI(65000, rt)
+ n1.SetPathIdentifier(30)
+ bits, err := n1.Serialize(opt)
+ assert.Nil(err)
+ n2 := NewRouteTargetMembershipNLRI(0, nil)
+ err = n2.DecodeFromBytes(bits, opt)
+ assert.Nil(err)
+ assert.Equal(n2.PathIdentifier(), uint32(30))
+ }
+ opt = &MarshallingOption{AddPath: map[RouteFamily]BGPAddPathMode{RF_EVPN: BGP_ADD_PATH_BOTH}}
+ {
+ n1 := NewEVPNNLRI(EVPN_ROUTE_TYPE_ETHERNET_AUTO_DISCOVERY, 0,
+ &EVPNEthernetAutoDiscoveryRoute{NewRouteDistinguisherFourOctetAS(5, 6),
+ EthernetSegmentIdentifier{ESI_ARBITRARY, make([]byte, 9)}, 2, 2})
+ n1.SetPathIdentifier(40)
+ bits, err := n1.Serialize(opt)
+ assert.Nil(err)
+ n2 := NewEVPNNLRI(0, 0, nil)
+ err = n2.DecodeFromBytes(bits, opt)
+ assert.Nil(err)
+ assert.Equal(n2.PathIdentifier(), uint32(40))
+ }
+ opt = &MarshallingOption{AddPath: map[RouteFamily]BGPAddPathMode{RF_IPv4_ENCAP: BGP_ADD_PATH_BOTH}}
+ {
+ n1 := NewEncapNLRI("10.10.10.0")
+ n1.SetPathIdentifier(50)
+ bits, err := n1.Serialize(opt)
+ assert.Nil(err)
+ n2 := NewEncapNLRI("")
+ err = n2.DecodeFromBytes(bits, opt)
+ assert.Nil(err)
+ assert.Equal(n2.PathIdentifier(), uint32(50))
+ }
+ opt = &MarshallingOption{AddPath: map[RouteFamily]BGPAddPathMode{RF_FS_IPv4_UC: BGP_ADD_PATH_BOTH}}
+ {
+ n1 := NewFlowSpecIPv4Unicast([]FlowSpecComponentInterface{NewFlowSpecDestinationPrefix(NewIPAddrPrefix(24, "10.0.0.0"))})
+ n1.SetPathIdentifier(60)
+ bits, err := n1.Serialize(opt)
+ assert.Nil(err)
+ n2 := NewFlowSpecIPv4Unicast(nil)
+ err = n2.DecodeFromBytes(bits, opt)
+ assert.Nil(err)
+ assert.Equal(n2.PathIdentifier(), uint32(60))
+ }
+ opt = &MarshallingOption{AddPath: map[RouteFamily]BGPAddPathMode{RF_OPAQUE: BGP_ADD_PATH_BOTH}}
+ {
+ n1 := NewOpaqueNLRI([]byte("key"), []byte("value"))
+ n1.SetPathIdentifier(70)
+ bits, err := n1.Serialize(opt)
+ assert.Nil(err)
+ n2 := &OpaqueNLRI{}
+ err = n2.DecodeFromBytes(bits, opt)
+ assert.Nil(err)
+ assert.Equal(n2.PathIdentifier(), uint32(70))
+ }
}
diff --git a/packet/bgp/validate_test.go b/packet/bgp/validate_test.go
index 225f941d..bcb74809 100644
--- a/packet/bgp/validate_test.go
+++ b/packet/bgp/validate_test.go
@@ -372,7 +372,7 @@ func Test_Validate_flowspec(t *testing.T) {
cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_FRAGMENT, []*FlowSpecComponentItem{item7}))
n1 := NewFlowSpecIPv4Unicast(cmp)
a := NewPathAttributeMpReachNLRI("", []AddrPrefixInterface{n1})
- m := map[RouteFamily]bool{RF_FS_IPv4_UC: true}
+ m := map[RouteFamily]BGPAddPathMode{RF_FS_IPv4_UC: BGP_ADD_PATH_NONE}
_, err := ValidateAttribute(a, m, false)
assert.Nil(err)