Newer
Older
"sync"
"time"
"github.com/bio-routing/bio-rd/protocols/bgp/packet"
"github.com/bio-routing/bio-rd/route"
"github.com/bio-routing/bio-rd/routingtable"
bnet "github.com/bio-routing/bio-rd/net"
log "github.com/sirupsen/logrus"
fsm *FSM
iBGP bool
rrClient bool
toSendMu sync.Mutex
toSend map[string]*pathPfxs
destroyCh chan struct{}
}
type pathPfxs struct {
path *route.Path
pfxs []bnet.Prefix
}
func newUpdateSender(fsm *FSM, afi uint16, safi uint8) *UpdateSender {
fsm: fsm,
iBGP: fsm.peer.localASN == fsm.peer.peerASN,
rrClient: fsm.peer.routeReflectorClient,
destroyCh: make(chan struct{}),
toSend: make(map[string]*pathPfxs),
// Start starts the update sender
func (u *UpdateSender) Start(aggrTime time.Duration) {
go u.sender(aggrTime)
}
// Destroy destroys everything (with greetings to Hatebreed)
func (u *UpdateSender) Destroy() {
u.destroyCh <- struct{}{}
}
// AddPath adds path p for pfx to toSend queue
func (u *UpdateSender) AddPath(pfx bnet.Prefix, p *route.Path) error {
u.toSendMu.Lock()
hash := p.BGPPath.ComputeHash()
if _, exists := u.toSend[hash]; exists {
u.toSend[hash].pfxs = append(u.toSend[hash].pfxs, pfx)
u.toSendMu.Unlock()
u.toSend[p.BGPPath.ComputeHash()] = &pathPfxs{
path: p,
pfxs: []bnet.Prefix{
pfx,
u.toSendMu.Unlock()
return nil
}
// sender serializes BGP update messages
func (u *UpdateSender) sender(aggrTime time.Duration) {
ticker := time.NewTicker(aggrTime)
var err error
var pathAttrs *packet.PathAttribute
var budget int
for {
select {
case <-u.destroyCh:
return
case <-ticker.C:
}
u.toSendMu.Lock()
for key, pathNLRIs := range u.toSend {
budget = packet.MaxLen - packet.HeaderLen - packet.MinUpdateLen - int(pathNLRIs.path.BGPPath.Length()) - overhead
Maximilian Wilhelm
committed
pathAttrs, err = packet.PathAttributes(pathNLRIs.path, u.iBGP, u.rrClient)
if err != nil {
log.Errorf("Unable to get path attributes: %v", err)
continue
}
updatesPrefixes := make([][]bnet.Prefix, 0, 1)
prefixes := make([]bnet.Prefix, 0, 1)
for _, pfx := range pathNLRIs.pfxs {
if u.fsm.options.AddPathRX {
budget -= 4
}
if budget < 0 {
updatesPrefixes = append(updatesPrefixes, prefixes)
budget = packet.MaxLen - int(pathNLRIs.path.BGPPath.Length()) - overhead
}
prefixes = append(prefixes, pfx)
}
if len(prefixes) > 0 {
updatesPrefixes = append(updatesPrefixes, prefixes)
}
delete(u.toSend, key)
u.toSendMu.Unlock()
u.sendUpdates(pathAttrs, updatesPrefixes, pathNLRIs.path.BGPPath.PathIdentifier)
u.toSendMu.Lock()
}
}
}
if !u.fsm.options.SupportsMultiProtocol {
return 0
addrLen := packet.IPv4AFI
if u.afi == packet.IPv6AFI {
addrLen = packet.IPv6Len
}
// since we are replacing the next hop attribute IPv4Len has to be subtracted, we also add another byte for extended length
return packet.AFILen + packet.SAFILen + 1 + addrLen - packet.IPv4Len + 1
func (u *UpdateSender) sendUpdates(pathAttrs *packet.PathAttribute, updatePrefixes [][]bnet.Prefix, pathID uint32) {
var err error
for _, prefixes := range updatePrefixes {
update := u.updateMessageForPrefixes(prefixes, pathAttrs, pathID)
if update == nil {
log.Errorf("Failed to create update: Neighbor does not support multi protocol.")
return
}
err = serializeAndSendUpdate(u.fsm.con, update, u.fsm.options)
if err != nil {
log.Errorf("Failed to serialize and send: %v", err)
}
func (u *UpdateSender) updateMessageForPrefixes(pfxs []bnet.Prefix, pa *packet.PathAttribute, pathID uint32) *packet.BGPUpdate {
if u.afi == packet.IPv4AFI && u.safi == packet.UnicastSAFI {
return u.bgpUpdate(pfxs, pa, pathID)
}
if u.fsm.options.SupportsMultiProtocol {
return u.bgpUpdateMultiProtocol(pfxs, pa, pathID)
}
}
func (u *UpdateSender) bgpUpdate(pfxs []bnet.Prefix, pa *packet.PathAttribute, pathID uint32) *packet.BGPUpdate {
update := &packet.BGPUpdate{
PathAttributes: pa,
}
var nlri *packet.NLRI
for _, pfx := range pfxs {
nlri = &packet.NLRI{
PathIdentifier: pathID,
IP: pfx.Addr().ToUint32(),
Pfxlen: pfx.Pfxlen(),
Next: update.NLRI,
}
return update
}
func (u *UpdateSender) bgpUpdateMultiProtocol(pfxs []bnet.Prefix, pa *packet.PathAttribute, pathID uint32) *packet.BGPUpdate {
pa, nextHop := u.copyAttributesWithoutNextHop(pa)
attrs := &packet.PathAttribute{
TypeCode: packet.MultiProtocolReachNLRICode,
Value: packet.MultiProtocolReachNLRI{
},
}
attrs.Next = pa
return &packet.BGPUpdate{
PathAttributes: attrs,
}
}
func (u *UpdateSender) copyAttributesWithoutNextHop(pa *packet.PathAttribute) (attrs *packet.PathAttribute, nextHop bnet.IP) {
var curCopy, lastCopy *packet.PathAttribute
if cur.TypeCode == packet.NextHopAttr {
nextHop = cur.Value.(bnet.IP)
} else {
curCopy = cur.Copy()
if lastCopy == nil {
attrs = curCopy
} else {
lastCopy.Next = curCopy
}
lastCopy = curCopy
}
}
func (u *UpdateSender) RemovePath(pfx bnet.Prefix, p *route.Path) bool {
if err != nil {
log.Errorf("Unable to withdraw prefix: %v", err)
return false
}
return true
func (u *UpdateSender) withdrawPrefix(pfx bnet.Prefix, p *route.Path) error {
if u.fsm.options.SupportsMultiProtocol {
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
return u.withDrawPrefixesMultiProtocol(u.fsm.con, pfx, p)
}
return u.withDrawPrefixesAddPath(u.fsm.con, pfx, p)
}
// withDrawPrefixes generates a BGPUpdate message and write it to the given
// io.Writer.
func (u *UpdateSender) withDrawPrefixes(out io.Writer, prefixes ...bnet.Prefix) error {
if len(prefixes) < 1 {
return nil
}
var rootNLRI *packet.NLRI
var currentNLRI *packet.NLRI
for _, pfx := range prefixes {
if rootNLRI == nil {
rootNLRI = &packet.NLRI{
IP: pfx.Addr().ToUint32(),
Pfxlen: pfx.Pfxlen(),
}
currentNLRI = rootNLRI
} else {
currentNLRI.Next = &packet.NLRI{
IP: pfx.Addr().ToUint32(),
Pfxlen: pfx.Pfxlen(),
}
currentNLRI = currentNLRI.Next
}
}
update := &packet.BGPUpdate{
WithdrawnRoutes: rootNLRI,
}
return serializeAndSendUpdate(out, update, u.fsm.options)
}
// withDrawPrefixesAddPath generates a BGPUpdateAddPath message and write it to the given
// io.Writer.
func (u *UpdateSender) withDrawPrefixesAddPath(out io.Writer, pfx bnet.Prefix, p *route.Path) error {
if p.Type != route.BGPPathType {
return errors.New("wrong path type, expected BGPPathType")
}
if p.BGPPath == nil {
return errors.New("got nil BGPPath")
}
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
update := &packet.BGPUpdate{
WithdrawnRoutes: &packet.NLRI{
PathIdentifier: p.BGPPath.PathIdentifier,
IP: pfx.Addr().ToUint32(),
Pfxlen: pfx.Pfxlen(),
},
}
return serializeAndSendUpdate(out, update, u.fsm.options)
}
func (u *UpdateSender) withDrawPrefixesMultiProtocol(out io.Writer, pfx bnet.Prefix, p *route.Path) error {
pathID := uint32(0)
if p.BGPPath != nil {
pathID = p.BGPPath.PathIdentifier
}
update := &packet.BGPUpdate{
PathAttributes: &packet.PathAttribute{
TypeCode: packet.MultiProtocolUnreachNLRICode,
Value: packet.MultiProtocolUnreachNLRI{
AFI: u.afi,
SAFI: u.safi,
Prefixes: []bnet.Prefix{pfx},
PathID: pathID,
},
},
return serializeAndSendUpdate(out, update, u.fsm.options)
func (u *UpdateSender) UpdateNewClient(client routingtable.RouteTableClient) error {
log.Warningf("BGP Update Sender: UpdateNewClient not implemented")
// RouteCount returns the number of stored routes
func (u *UpdateSender) RouteCount() int64 {
log.Warningf("BGP Update Sender: RouteCount not implemented")
return 0
}