Files
fgbgp/messages/bgp_update.go
2018-03-23 18:59:10 +01:00

798 lines
19 KiB
Go

package messages
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
"net"
"time"
)
type BGPAttribute_NEXTHOP struct {
NextHop net.IP
}
type BGPAttribute_ORIGIN struct {
Origin byte
}
type BGPAttribute_MED struct {
Med uint32
}
type BGPAttribute_LOCPREF struct {
LocPref uint32
}
type BGPAttribute_COMMUNITIES struct {
Communities []uint32
}
type ASPath_Segment struct {
SType byte
ASPath []uint32
}
type BGPAttribute_ASPATH struct {
Segments []ASPath_Segment
Enc2Bytes bool
}
type BGPAttribute_MP_UNREACH struct {
Afi uint16
Safi byte
NLRI []NLRI
EnableAddPath bool
}
type BGPAttribute_MP_REACH struct {
Afi uint16
Safi byte
NextHop net.IP
NLRI []NLRI
EnableAddPath bool
}
type BGPAttribute_ATOMIC_AGGREGATE struct {
}
type BGPAttribute_AGGREGATOR struct {
ASN uint32
Identifier []byte
Enc2Bytes bool
}
type BGPAttributeIf SerializableInterface
type BGPAttribute struct {
Flags byte
Code byte
Data []byte
}
type BGPMessageUpdate struct {
BGPMessageHead
WithdrawnRoutes []NLRI
PathAttributes []BGPAttributeIf
NLRI []NLRI
EnableAddPath bool
}
func (m BGPAttribute_ORIGIN) String() string {
return fmt.Sprintf("Origin: %v", m.Origin)
}
func (m BGPAttribute_AGGREGATOR) String() string {
id := net.IP(m.Identifier)
return fmt.Sprintf("Aggregator: ASN: %v / Id: %v", m.ASN, id)
}
func (m BGPAttribute_ATOMIC_AGGREGATE) String() string {
return "Atomic aggregate"
}
func (m BGPAttribute_MED) String() string {
return fmt.Sprintf("Med: %v", m.Med)
}
func (m BGPAttribute_LOCPREF) String() string {
return fmt.Sprintf("LocPref: %v", m.LocPref)
}
func (m BGPAttribute_ASPATH) String() string {
return fmt.Sprintf("ASPath: %v", m.Segments)
}
func (m ASPath_Segment) String() string {
return fmt.Sprintf("Segment (type: %v | len: %v): %v", m.SType, len(m.ASPath), m.ASPath)
}
func (m BGPAttribute_COMMUNITIES) String() string {
var comlist string
for i := range m.Communities {
comlist += fmt.Sprintf("%v:%v, ", m.Communities[i]&0xFFFF0000>>16, m.Communities[i]&0xFFFF)
}
return fmt.Sprintf("Communities: [ %v]", comlist)
}
func (m BGPAttribute_MP_REACH) String() string {
var NLRI string
for i := range m.NLRI {
NLRI += m.NLRI[i].String() + ", "
}
return fmt.Sprintf("MP Reach: %v-%v (%v) (%v) / Nexthop: %v / NLRI: [ %v]", AfiToStr[m.Afi], SafiToStr[m.Safi], m.Afi, m.Safi, m.NextHop, NLRI)
}
func (m BGPAttribute_MP_UNREACH) String() string {
var NLRI string
for i := range m.NLRI {
NLRI += m.NLRI[i].String() + ", "
}
return fmt.Sprintf("MP Unreach: %v-%v (%v) (%v) / NLRI: [ %v]", AfiToStr[m.Afi], SafiToStr[m.Safi], m.Afi, m.Safi, NLRI)
}
func (m BGPAttribute_NEXTHOP) String() string {
return fmt.Sprintf("Nexthop %v", m.NextHop.String())
}
func (m BGPAttribute) String() string {
str := "%b %v (%v): %v"
return fmt.Sprintf(str, m.Flags, BgpAttributes[int(m.Code)], m.Code, m.Data)
}
func (m BGPMessageUpdate) String() string {
// To be completed
return fmt.Sprintf("BGP Update: Withdraw: %v / PathAttributes: %v / NLRI: %v", m.WithdrawnRoutes, m.PathAttributes, m.NLRI)
}
func (m BGPMessageUpdate) LenWithdrawn() int {
var sumW int
for i := range m.WithdrawnRoutes {
sumW += m.WithdrawnRoutes[i].Len(m.EnableAddPath)
}
return sumW
}
func (m BGPMessageUpdate) LenPathAttribute() int {
var sumPA int
for i := range m.PathAttributes {
sumPA += m.PathAttributes[i].Len()
}
return sumPA
}
func (m BGPMessageUpdate) LenContent() int {
sumW := m.LenWithdrawn()
sumPA := m.LenPathAttribute()
var sumA int
for i := range m.NLRI {
sumA += m.NLRI[i].Len(m.EnableAddPath)
}
return 2 + sumW + 2 + sumPA + sumA
}
func (m BGPMessageUpdate) Len() int {
return GetBGPHeaderLen() + m.LenContent()
}
func (m BGPMessageUpdate) Write(bw io.Writer) {
WriteBGPHeader(MESSAGE_UPDATE, uint16(m.LenContent()), bw)
binary.Write(bw, binary.BigEndian, uint16(m.LenWithdrawn()))
for i := range m.WithdrawnRoutes {
m.WithdrawnRoutes[i].Write(bw, m.EnableAddPath)
}
binary.Write(bw, binary.BigEndian, uint16(m.LenPathAttribute()))
for i := range m.PathAttributes {
m.PathAttributes[i].Write(bw)
}
for i := range m.NLRI {
m.NLRI[i].Write(bw, m.EnableAddPath)
}
}
func (m BGPAttribute_ORIGIN) Len() int {
return AttributeHeaderLen(1) + 1
}
func (m BGPAttribute_ORIGIN) Write(bw io.Writer) {
binary.Write(bw, binary.BigEndian, byte(ATTRIBUTE_TRANSITIVE))
binary.Write(bw, binary.BigEndian, byte(ATTRIBUTE_ORIGIN))
binary.Write(bw, binary.BigEndian, byte(1))
binary.Write(bw, binary.BigEndian, m.Origin)
}
func (m BGPAttribute_AGGREGATOR) Len() int {
return AttributeHeaderLen(8) + 8
}
func (m BGPAttribute_AGGREGATOR) Write(bw io.Writer) {
// May cause issue as ASN is 32 bits
binary.Write(bw, binary.BigEndian, byte(ATTRIBUTE_OPTIONAL))
binary.Write(bw, binary.BigEndian, byte(ATTRIBUTE_AGGREGATOR))
binary.Write(bw, binary.BigEndian, byte(8))
binary.Write(bw, binary.BigEndian, m.ASN)
binary.Write(bw, binary.BigEndian, m.Identifier)
}
func (m BGPAttribute_ATOMIC_AGGREGATE) Len() int {
return AttributeHeaderLen(0)
}
func (m BGPAttribute_ATOMIC_AGGREGATE) Write(bw io.Writer) {
WriteAttributeHeader(bw, 0, ATTRIBUTE_OPTIONAL, ATTRIBUTE_ATOMIC_AGGREGATE)
}
func (m BGPAttribute_MED) Len() int {
return AttributeHeaderLen(4) + 4
}
func (m BGPAttribute_MED) Write(bw io.Writer) {
binary.Write(bw, binary.BigEndian, byte(ATTRIBUTE_OPTIONAL))
binary.Write(bw, binary.BigEndian, byte(ATTRIBUTE_MED))
binary.Write(bw, binary.BigEndian, byte(4))
binary.Write(bw, binary.BigEndian, m.Med)
}
func (m BGPAttribute_LOCPREF) Len() int {
return AttributeHeaderLen(4) + 4
}
func (m BGPAttribute_LOCPREF) Write(bw io.Writer) {
WriteAttributeHeader(bw, 4, ATTRIBUTE_OPTIONAL, ATTRIBUTE_LOCPREF)
binary.Write(bw, binary.BigEndian, m.LocPref)
}
func (m BGPAttribute_ASPATH) Len() int {
var size int
for i := range m.Segments {
size += m.Segments[i].LenContent(m.Enc2Bytes)
}
return AttributeHeaderLen(size) + size
}
func (m BGPAttribute_ASPATH) Write(bw io.Writer) {
WriteAttributeHeader(bw, m.LenContent(), ATTRIBUTE_TRANSITIVE, ATTRIBUTE_ASPATH)
if len(m.Segments) == 0 {
return
}
for i := range m.Segments {
m.Segments[i].Write(bw, m.Enc2Bytes)
}
}
func (m BGPAttribute_ASPATH) LenContent() int {
var size int
for i := range m.Segments {
size += m.Segments[i].LenContent(m.Enc2Bytes)
}
return size
}
func (m ASPath_Segment) LenSets() int {
aspathlen := len(m.ASPath)
itera := aspathlen / 0xff
if aspathlen%0xff != 0 {
itera += 1
}
return itera
}
func (m ASPath_Segment) LenContent(enc2bytes bool) int {
if len(m.ASPath) == 0 {
return 0
}
numsets := m.LenSets()
if enc2bytes {
return 2*numsets + 2*len(m.ASPath)
}
return 2*numsets + 4*len(m.ASPath)
}
func (m ASPath_Segment) Write(bw io.Writer, enc2bytes bool) {
if len(m.ASPath) == 0 {
return
}
itera := m.LenSets()
var cursetlen byte
for i := 0; i < itera; i++ {
cursetlen = 0xff
if i == itera-1 {
cursetlen = byte(len(m.ASPath) % 0xff)
}
binary.Write(bw, binary.BigEndian, m.SType)
binary.Write(bw, binary.BigEndian, byte(cursetlen))
for j := 0xff * i; j < len(m.ASPath) && j < 0xff*(i+1); j++ {
if enc2bytes {
binary.Write(bw, binary.BigEndian, uint16(m.ASPath[j]))
} else {
binary.Write(bw, binary.BigEndian, m.ASPath[j])
}
}
}
}
func AttributeHeaderLen(size int) int {
if size > 0xff {
return 4
} else {
return 3
}
}
func IPtoBytes(ip net.IP) []byte {
if ip.To4() == nil {
return ip.To16()
}
return ip.To4()
}
func WriteAttributeHeader(bw io.Writer, size int, attrflag byte, attrcode byte) {
var extended byte
if size > 0xff {
extended = ATTRIBUTE_EXTENDED
}
binary.Write(bw, binary.BigEndian, byte(attrflag|extended))
binary.Write(bw, binary.BigEndian, attrcode)
if extended != 0 {
binary.Write(bw, binary.BigEndian, byte((size&0xff00)>>8))
}
binary.Write(bw, binary.BigEndian, byte(size&0xff))
}
func (m BGPAttribute_COMMUNITIES) LenContent() int {
return 4 * len(m.Communities)
}
func (m BGPAttribute_COMMUNITIES) Len() int {
size := m.LenContent()
return AttributeHeaderLen(size) + size
}
func (m BGPAttribute_COMMUNITIES) Write(bw io.Writer) {
WriteAttributeHeader(bw, m.LenContent(), ATTRIBUTE_TRANSITIVEOPT, ATTRIBUTE_COMMUNITIES)
for i := range m.Communities {
binary.Write(bw, binary.BigEndian, m.Communities[i])
}
}
func (m BGPAttribute_MP_REACH) LenMrt() uint16 {
ip := IPtoBytes(m.NextHop)
return 2 + 1 + 1 + uint16(len(ip))
}
func (m BGPAttribute_MP_REACH) WriteMrt(buf io.Writer) {
binary.Write(buf, binary.BigEndian, byte(ATTRIBUTE_OPTIONAL))
binary.Write(buf, binary.BigEndian, byte(ATTRIBUTE_REACH))
nhb := IPtoBytes(m.NextHop)
lengthnh := len(nhb)
binary.Write(buf, binary.BigEndian, byte(1+lengthnh))
binary.Write(buf, binary.BigEndian, byte(lengthnh))
binary.Write(buf, binary.BigEndian, nhb)
}
func (m BGPAttribute_MP_REACH) GetNextHopLen() int {
return len(IPtoBytes(m.NextHop))
}
func (m BGPAttribute_MP_REACH) ContentLen() int {
var sum int
for i := range m.NLRI {
sum += m.NLRI[i].Len(m.EnableAddPath)
}
size := 4 + m.GetNextHopLen() + 1 + sum
return size
}
func (m BGPAttribute_MP_REACH) Len() int {
size := m.ContentLen()
return AttributeHeaderLen(size) + size
}
func (m BGPAttribute_MP_REACH) Write(bw io.Writer) {
WriteAttributeHeader(bw, m.ContentLen(), ATTRIBUTE_OPTIONAL, ATTRIBUTE_REACH)
binary.Write(bw, binary.BigEndian, m.Afi)
binary.Write(bw, binary.BigEndian, m.Safi)
binary.Write(bw, binary.BigEndian, byte(m.GetNextHopLen()))
binary.Write(bw, binary.BigEndian, IPtoBytes(m.NextHop))
binary.Write(bw, binary.BigEndian, byte(0))
for i := range m.NLRI {
m.NLRI[i].Write(bw, m.EnableAddPath)
}
}
func (m BGPAttribute_MP_UNREACH) ContentLen() int {
var sum int
for i := range m.NLRI {
sum += m.NLRI[i].Len(m.EnableAddPath)
}
size := 3 + sum
return size
}
func (m BGPAttribute_MP_UNREACH) Len() int {
size := m.ContentLen()
return AttributeHeaderLen(size) + size
}
func (m BGPAttribute_MP_UNREACH) Write(bw io.Writer) {
WriteAttributeHeader(bw, m.ContentLen(), ATTRIBUTE_OPTIONAL, ATTRIBUTE_UNREACH)
binary.Write(bw, binary.BigEndian, m.Afi)
binary.Write(bw, binary.BigEndian, m.Safi)
for i := range m.NLRI {
m.NLRI[i].Write(bw, m.EnableAddPath)
}
}
func (m BGPAttribute_NEXTHOP) ContentLen() int {
ip := IPtoBytes(m.NextHop)
return len(ip)
}
func (m BGPAttribute_NEXTHOP) Len() int {
size := m.ContentLen()
return AttributeHeaderLen(size) + size
}
func (m BGPAttribute_NEXTHOP) Write(bw io.Writer) {
WriteAttributeHeader(bw, m.ContentLen(), ATTRIBUTE_TRANSITIVE, ATTRIBUTE_NEXTHOP)
ip := IPtoBytes(m.NextHop)
binary.Write(bw, binary.BigEndian, ip)
}
func (m BGPAttribute) Len() int {
size := len(m.Data)
return AttributeHeaderLen(size) + size
}
func (m BGPAttribute) Write(bw io.Writer) {
WriteAttributeHeader(bw, len(m.Data), m.Flags, m.Code)
binary.Write(bw, binary.BigEndian, m.Data)
}
/*func (m *BGPMessageUpdate) AddASNToPath(asn uint32) {
for i := range(m.PathAttributes) {
if v,ok := m.PathAttributes[i].(BGPAttribute_ASPATH); ok {
v.ASPath = append(v.ASPath, asn)
m.PathAttributes[i] = v
return
}
}
m.PathAttributes = append(m.PathAttributes, BGPAttribute_ASPATH{
SType: 2,
ASPath: []uint32{asn,},
})
}*/
func ParseNLRI(b []byte, afi uint16, safi byte, path bool) ([]NLRI, error) {
prefixlist := make([]NLRI, 0)
if afi != AFI_IPV4 && afi != AFI_IPV6 {
return prefixlist, errors.New(fmt.Sprintf("ParseNLRI: cannot decode this Afi/Safi %v/%v", afi, safi))
}
psize := 32
asize := 4
if afi == AFI_IPV6 {
psize = 128
asize = 16
}
i := 0
for i < len(b) {
var pathid uint32
if path {
if len(b)-i < 5 {
return nil, errors.New(fmt.Sprintf("ParseNLRI: wrong NLRI size with add-path: %v < 5", len(b)))
}
pathid = uint32(b[i])<<24 | uint32(b[i+1])<<16 | uint32(b[i+2])<<8 | uint32(b[i+3])
i += 4
}
length := int(b[i])
lengthb := length
add := 0
if length%8 != 0 {
add = 1
}
length = length/8 + add
i++
if i+length > len(b) {
return prefixlist, errors.New(fmt.Sprintf("ParseNLRI: wrong NLRI size: %v > %v", i+length, len(b)))
}
prefix := b[i : i+length]
mask := net.CIDRMask(lengthb, psize)
ip := make([]byte, asize)
if len(prefix) > len(ip) {
return prefixlist, errors.New(fmt.Sprintf("ParseNLRI: wrong IP size: %v > %v", len(prefix), len(ip)))
}
for j := range prefix {
ip[j] = prefix[j]
}
ipnet := net.IPNet{
IP: ip,
Mask: mask,
}
prefixlist = append(prefixlist, NLRI_IPPrefix{
Prefix: ipnet,
PathId: pathid,
})
i += length
}
return prefixlist, nil
}
func ParsePathAttribute(b []byte, addpathlist []AfiSafi, enc2bytes bool) ([]BGPAttributeIf, error) {
attributes := make([]BGPAttributeIf, 0)
i := 0
for i < len(b) {
if len(b)-i < 3 {
return attributes, errors.New(fmt.Sprintf("ParsePathAttribute: attribute size (need 3 bytes, got %v)", len(b)-i))
}
attrflag := b[i]
attrcode := b[i+1]
extended := byte((attrflag & ATTRIBUTE_EXTENDED) >> 4)
length := int(b[i+2])
if extended != 0 && i+3 > len(b)-1 {
return attributes, errors.New(fmt.Sprintf("ParsePathAttribute: wrong extended size: %v > %v", i+3, len(b)-1))
}
offset := 0
if extended != 0 {
length = int(uint16(b[i+2])<<8 | uint16(b[i+3]))
offset = 1
}
if i+offset+3+length > len(b) || i+offset+3 > len(b) {
return attributes, errors.New(fmt.Sprintf("ParsePathAttribute: wrong size: %v > %v or %v > %v (ext: %v / %v)", i+offset+3+length, len(b), i+offset+3, len(b), i, extended))
}
data := b[i+offset+3 : i+offset+3+length]
if i+3+offset+length > len(b) {
return attributes, errors.New(fmt.Sprintf("ParsePathAttribute: wrong attribute size: %v > %v", i+3+length, len(b)))
}
var intf SerializableInterface
buf := bytes.NewBuffer(data)
switch attrcode {
case ATTRIBUTE_ORIGIN:
o := byte(2)
if len(data) > 0 {
o = data[0]
} else {
return attributes, errors.New(fmt.Sprintf("ParsePathAttribute: empty data for ORIGIN attribute"))
}
a := BGPAttribute_ORIGIN{
Origin: o,
}
intf = a
case ATTRIBUTE_MED:
a := BGPAttribute_MED{}
binary.Read(buf, binary.BigEndian, &(a.Med))
intf = a
case ATTRIBUTE_AGGREGATOR:
a := BGPAttribute_AGGREGATOR{}
if len(data) == 8 && !enc2bytes {
binary.Read(buf, binary.BigEndian, &(a.ASN))
a.Identifier = data[4:8]
} else if len(data) == 6 && enc2bytes {
var tmpas uint16
binary.Read(buf, binary.BigEndian, &tmpas)
a.ASN = uint32(tmpas)
a.Identifier = data[2:6]
}
a.Enc2Bytes = enc2bytes
intf = a
case ATTRIBUTE_ATOMIC_AGGREGATE:
a := BGPAttribute_ATOMIC_AGGREGATE{}
intf = a
case ATTRIBUTE_LOCPREF:
a := BGPAttribute_LOCPREF{}
binary.Read(buf, binary.BigEndian, &(a.LocPref))
intf = a
case ATTRIBUTE_ASPATH:
a := BGPAttribute_ASPATH{Segments: make([]ASPath_Segment, 0)}
var aslen byte
var err_rd error
var stype byte
stype, err_rd = buf.ReadByte()
for err_rd == nil {
aslen, err_rd = buf.ReadByte()
if err_rd != nil {
break
}
s := ASPath_Segment{SType: stype, ASPath: make([]uint32, 0)}
if err_rd != nil {
break
}
if !enc2bytes {
var tmpas uint32
if err_rd != nil {
break
}
for j := 0; j < int(aslen) && j <= 255; j++ {
binary.Read(buf, binary.BigEndian, &tmpas)
s.ASPath = append(s.ASPath, tmpas)
}
} else {
var tmpas uint16
if err_rd != nil {
break
}
for j := 0; j < int(aslen) && j <= 255; j++ {
binary.Read(buf, binary.BigEndian, &tmpas)
s.ASPath = append(s.ASPath, uint32(tmpas))
}
}
a.Segments = append(a.Segments, s)
stype, err_rd = buf.ReadByte()
if err_rd != nil {
break
}
}
a.Enc2Bytes = enc2bytes
intf = a
case ATTRIBUTE_NEXTHOP:
intf = BGPAttribute_NEXTHOP{NextHop: data[0:4]}
case ATTRIBUTE_COMMUNITIES:
a := BGPAttribute_COMMUNITIES{Communities: make([]uint32, length/4)}
for j := 0; j < length/4; j++ {
binary.Read(buf, binary.BigEndian, &(a.Communities[j]))
}
intf = a
case ATTRIBUTE_REACH:
a := BGPAttribute_MP_REACH{}
binary.Read(buf, binary.BigEndian, &(a.Afi))
binary.Read(buf, binary.BigEndian, &(a.Safi))
nhlen, _ := buf.ReadByte()
nh := make([]byte, nhlen)
buf.Read(nh)
a.NextHop = nh
buf.ReadByte()
parseinfo := InAfiSafi(a.Afi, a.Safi, addpathlist)
a.NLRI, _ = ParseNLRI(buf.Bytes(), a.Afi, a.Safi, parseinfo)
a.EnableAddPath = parseinfo
intf = a
case ATTRIBUTE_UNREACH:
a := BGPAttribute_MP_UNREACH{}
binary.Read(buf, binary.BigEndian, &(a.Afi))
binary.Read(buf, binary.BigEndian, &(a.Safi))
parseinfo := InAfiSafi(a.Afi, a.Safi, addpathlist)
a.NLRI, _ = ParseNLRI(buf.Bytes(), a.Afi, a.Safi, parseinfo)
intf = a
default:
intf = BGPAttribute{
attrflag,
attrcode,
data,
}
}
attributes = append(attributes, intf)
i += 3 + length + offset
}
return attributes, nil
}
func ParseUpdate(b []byte, addpathlist []AfiSafi, enc2bytes bool) (*BGPMessageUpdate, error) {
m := &BGPMessageUpdate{}
var err error
addpath_ipv4uni := InAfiSafi(AFI_IPV4, SAFI_UNICAST, addpathlist)
m.EnableAddPath = addpath_ipv4uni
if len(b) < 4 {
return nil, errors.New(fmt.Sprintf("ParseUpdate: wrong withdrawn routes size: %v < 4", len(b)))
}
wdrouteslen := int(uint16(b[0])<<8 | uint16(b[1]))
if wdrouteslen+4 > len(b) {
return nil, errors.New(fmt.Sprintf("ParseUpdate: wrong withdrawn routes size: %v > %v", wdrouteslen+4, len(b)))
}
offset := 2
withdrawnroutes := b[offset : offset+wdrouteslen]
m.WithdrawnRoutes, err = ParseNLRI(withdrawnroutes, AFI_IPV4, SAFI_UNICAST, addpath_ipv4uni)
if err != nil {
return nil, err
}
offset += wdrouteslen
tplen := int(uint16(b[offset])<<8 | uint16(b[offset+1]))
offset += 2
if tplen+offset > len(b) {
return nil, errors.New(fmt.Sprintf("ParseUpdate: wrong total path size: %v > %v", tplen+offset, len(b)))
}
pathattributes := b[offset : offset+tplen]
m.PathAttributes, err = ParsePathAttribute(pathattributes, addpathlist, enc2bytes)
if err != nil {
return m, err
}
offset += tplen
NLRI := b[offset:]
m.NLRI, err = ParseNLRI(NLRI, AFI_IPV4, SAFI_UNICAST, addpath_ipv4uni)
if err != nil {
return m, err
}
return m, nil
}
func CraftUpdateMessage() *BGPMessageUpdate {
//_, prefix, _ := net.ParseCIDR("8.8.8.8/24")
_, prefixtest, _ := net.ParseCIDR("2001::/46")
ip := net.ParseIP("2002::1")
pa := []BGPAttributeIf{
BGPAttribute_ORIGIN{
Origin: 2,
},
BGPAttribute_ASPATH{
Segments: []ASPath_Segment{ASPath_Segment{ASPath: []uint32{65001}}},
},
BGPAttribute_COMMUNITIES{
Communities: []uint32{0x7b0929},
},
//BGPAttribute_NEXTHOP{
// NextHop: []byte{1,2,3,4},
//},
BGPAttribute_MP_REACH{
Afi: AFI_IPV6,
Safi: SAFI_UNICAST,
NextHop: ip,
//enableAddPath: true,
NLRI: []NLRI{
NLRI_IPPrefix{
PathId: uint32(time.Now().UTC().Unix()),
Prefix: *prefixtest,
},
},
},
}
m := &BGPMessageUpdate{
//NLRI: []NLRI{NLRI{Prefix: *prefix,PathId:123,},},
PathAttributes: pa,
}
return m
}