diff --git a/protocols/bgp/server/update_sender_add_path.go b/protocols/bgp/server/update_sender_add_path.go index 66d4a594cc6b59852bf206447c59cdb949d25abf..9d4820a3f3d7ed8a57ea821d3714f192053fe03e 100644 --- a/protocols/bgp/server/update_sender_add_path.go +++ b/protocols/bgp/server/update_sender_add_path.go @@ -1,9 +1,12 @@ package server import ( + "sync" + "time" + log "github.com/sirupsen/logrus" - "github.com/bio-routing/bio-rd/net" + bnet "github.com/bio-routing/bio-rd/net" "github.com/bio-routing/bio-rd/protocols/bgp/packet" "github.com/bio-routing/bio-rd/route" "github.com/bio-routing/bio-rd/routingtable" @@ -12,38 +15,101 @@ import ( // UpdateSenderAddPath converts table changes into BGP update messages with add path type UpdateSenderAddPath struct { routingtable.ClientManager - fsm *FSM - iBGP bool + fsm *FSM + iBGP bool + buffer chan *route.Route + toSendMu sync.Mutex + toSend map[string]struct { + path *route.Path + pfxs []bnet.Prefix + } } func newUpdateSenderAddPath(fsm *FSM) *UpdateSenderAddPath { return &UpdateSenderAddPath{ - fsm: fsm, - iBGP: fsm.peer.localASN == fsm.peer.peerASN, + fsm: fsm, + iBGP: fsm.peer.localASN == fsm.peer.peerASN, + buffer: make(chan *route.Route, 1000), } } -// AddPath serializes a new path and sends out a BGP update message -func (u *UpdateSenderAddPath) AddPath(pfx net.Prefix, p *route.Path) error { - pathAttrs, err := pathAttribues(p) +func (u *UpdateSenderAddPath) AddPath(pfx bnet.Prefix, p *route.Path) error { + u.buffer <- route.NewRoute(pfx, p) + return nil +} + +// sender serializes BGP update messages +func (u *UpdateSenderAddPath) sender() { + ticker := time.NewTicker(time.Millisecond * 5) + var r *route.Route + var p *route.Path + var pfx bnet.Prefix + var err error + var pathAttrs *packet.PathAttribute + var update *packet.BGPUpdateAddPath + var lastNLRI *packet.NLRIAddPath + var budget int64 - if err != nil { - log.Errorf("Unable to create BGP Update: %v", err) - return nil - } - update := &packet.BGPUpdateAddPath{ - PathAttributes: pathAttrs, - NLRI: &packet.NLRIAddPath{ - PathIdentifier: p.BGPPath.PathIdentifier, - IP: pfx.Addr(), - Pfxlen: pfx.Pfxlen(), - }, + for { + <-ticker.C + u.toSendMu.Lock() + + for _, pathNLRIs := range u.toSend { + budget = packet.MaxLen + + pathAttrs, err = pathAttribues(pathNLRIs.path) + if err != nil { + log.Errorf("Unable to get path attributes: %v", err) + continue + } + + update = &packet.BGPUpdateAddPath{ + PathAttributes: pathAttrs, + /*NLRI: &packet.NLRIAddPath{ + PathIdentifier: p.BGPPath.PathIdentifier, + IP: pfx.Addr(), + Pfxlen: pfx.Pfxlen(), + },*/ + } + + for _, pfx := range pathNLRIs.pfxs { + nlri = &packet.NLRIAddPath{ + PathIdentifier: pathNLRIs.path.BGPPath.PathIdentifier, + IP: pfx.Addr(), + Pfxlen: pfx.Pfxlen(), + } + } + } + + u.toSendMu.Unlock() + + p = r.Paths()[0] + pfx = r.Prefix() + pathAttrs, err = pathAttribues(p) + + if err != nil { + log.Errorf("Unable to create BGP Update: %v", err) + continue + } + update = &packet.BGPUpdateAddPath{ + PathAttributes: pathAttrs, + NLRI: &packet.NLRIAddPath{ + PathIdentifier: p.BGPPath.PathIdentifier, + IP: pfx.Addr(), + Pfxlen: pfx.Pfxlen(), + }, + } + + err = serializeAndSendUpdate(u.fsm.con, update, u.fsm.options) + if err != nil { + log.Errorf("Failed to serialize and send: %v", err) + } } - return serializeAndSendUpdate(u.fsm.con, update, u.fsm.options) + } // RemovePath withdraws prefix `pfx` from a peer -func (u *UpdateSenderAddPath) RemovePath(pfx net.Prefix, p *route.Path) bool { +func (u *UpdateSenderAddPath) RemovePath(pfx bnet.Prefix, p *route.Path) bool { err := withDrawPrefixesAddPath(u.fsm.con, u.fsm.options, pfx, p) return err == nil } diff --git a/route/bgp_path.go b/route/bgp_path.go index 0ab7dc4b2a3f6a23d77be1a0613b68515a5d1604..d28f586d1cc7059cad7b4c2ead5a3394ff1f2777 100644 --- a/route/bgp_path.go +++ b/route/bgp_path.go @@ -25,6 +25,17 @@ type BGPPath struct { LargeCommunities []packet.LargeCommunity } +// Legth get's the length of serialized path +func (b *BGPPath) Legth() uint16 { + asPathLen := uint16(3) + for _, segment := range b.ASPath { + asPathLen++ + asPathLen += uint16(4 * len(segment.ASNs)) + } + + return uint16(len(b.Communities))*7 + uint16(len(b.LargeCommunities))*15 + 4*7 + 4 + asPathLen +} + // ECMP determines if routes b and c are euqal in terms of ECMP func (b *BGPPath) ECMP(c *BGPPath) bool { return b.LocalPref == c.LocalPref && b.ASPathLen == c.ASPathLen && b.MED == c.MED && b.Origin == c.Origin