diff --git a/protocols/bgp/packet/decoder.go b/protocols/bgp/packet/decoder.go index 6431053338492e8981cd513ee6ecdd9b69511e89..31583bf1b68257625dfaa3d8b8e40893982d6713 100644 --- a/protocols/bgp/packet/decoder.go +++ b/protocols/bgp/packet/decoder.go @@ -114,11 +114,7 @@ func decodeNotificationMsg(buf *bytes.Buffer) (*BGPNotification, error) { return invalidErrCode(msg) } case Cease: -<<<<<<< HEAD if !(msg.ErrorSubcode == 0 || msg.ErrorSubcode == AdministrativeShutdown || msg.ErrorSubcode == AdministrativeReset) { -======= - if msg.ErrorSubcode == 0 || msg.ErrorSubcode > 8 { ->>>>>>> 453a853eeb0507c5e83706d9e3f251adba5b2484 return invalidErrCode(msg) } default: diff --git a/protocols/bgp/server/fsm.go b/protocols/bgp/server/fsm.go deleted file mode 100644 index a26a743d7d85245a431483c05d35a2d1d4d09f63..0000000000000000000000000000000000000000 --- a/protocols/bgp/server/fsm.go +++ /dev/null @@ -1,959 +0,0 @@ -package server - -import ( - "bytes" - "fmt" - "math" - "net" - "time" - - "github.com/bio-routing/bio-rd/routingtable" - - "github.com/bio-routing/bio-rd/config" - tnet "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/adjRIBIn" - "github.com/bio-routing/bio-rd/routingtable/adjRIBOut" - "github.com/bio-routing/bio-rd/routingtable/adjRIBOutAddPath" - log "github.com/sirupsen/logrus" - tomb "gopkg.in/tomb.v2" -) - -const ( - // Administrative events - ManualStart = 1 - ManualStop = 2 - AutomaticStart = 3 - ManualStartWithPassiveTcpEstablishment = 4 - AutomaticStartWithPassiveTcpEstablishment = 5 - AutomaticStop = 8 - - // Timer events - ConnectRetryTimerExpires = 9 - HoldTimerExpires = 10 - KeepaliveTimerExpires = 11 -) - -const ( - Cease = 0 - Idle = 1 - Connect = 2 - Active = 3 - OpenSent = 4 - OpenConfirm = 5 - Established = 6 -) - -type FSM struct { - peer *Peer - - t tomb.Tomb - stateReason string - state int - lastState int - eventCh chan int - - con *net.TCPConn - con2 *net.TCPConn - conCh chan *net.TCPConn - conErrCh chan error - initiateCon chan struct{} - passive bool - - local net.IP - remote net.IP - - localASN uint16 - remoteASN uint16 - - neighborID uint32 - routerID uint32 - - delayOpen bool - delayOpenTime time.Duration - delayOpenTimer *time.Timer - - connectRetryTime time.Duration - connectRetryTimer *time.Timer - connectRetryCounter int - - holdTimeConfigured time.Duration - holdTime time.Duration - holdTimer *time.Timer - - keepaliveTime time.Duration - keepaliveTimer *time.Ticker - - msgRecvCh chan msgRecvMsg - msgRecvFailCh chan msgRecvErr - stopMsgRecvCh chan struct{} - - adjRIBIn *adjRIBIn.AdjRIBIn - adjRIBOut routingtable.RouteTableClient - rib routingtable.RouteTableClient - updateSender routingtable.RouteTableClient - - capAddPathSend bool - capAddPathRecv bool -} - -type msgRecvMsg struct { - msg []byte - con *net.TCPConn -} - -type msgRecvErr struct { - err error - con *net.TCPConn -} - -func NewFSM(peer *Peer, c config.Peer, rib routingtable.RouteTableClient) *FSM { - fsm := &FSM{ - peer: peer, - state: Idle, - passive: true, - connectRetryTime: 5, - connectRetryTimer: time.NewTimer(time.Second * time.Duration(20)), - - msgRecvCh: make(chan msgRecvMsg), - msgRecvFailCh: make(chan msgRecvErr), - stopMsgRecvCh: make(chan struct{}), - - holdTimeConfigured: time.Duration(c.HoldTimer), - holdTimer: time.NewTimer(0), - - keepaliveTime: time.Duration(c.KeepAlive), - keepaliveTimer: time.NewTicker(time.Duration(c.KeepAlive)), - - routerID: c.RouterID, - remote: c.PeerAddress, - local: c.LocalAddress, - localASN: uint16(c.LocalAS), - eventCh: make(chan int), - conCh: make(chan *net.TCPConn), - conErrCh: make(chan error), initiateCon: make(chan struct{}), - - rib: rib, - } - - return fsm -} - -func (fsm *FSM) disconnect() { - if fsm.con != nil { - fsm.con.Close() - fsm.con = nil - } - if fsm.con2 != nil { - fsm.con2.Close() - fsm.con2 = nil - } -} - -func (fsm *FSM) changeState(new int, reason string) int { - state := map[int]string{ - Cease: "Cease", - Idle: "Idle", - Connect: "Connect", - Active: "Active", - OpenSent: "OpenSent", - OpenConfirm: "OpenConfirm", - Established: "Established", - } - - log.WithFields(log.Fields{ - "peer": fsm.remote.String(), - "last_state": state[fsm.state], - "new_state": state[new], - "reason": reason, - }).Info("FSM: Neighbor state change") - - fsm.lastState = fsm.state - fsm.state = new - fsm.stateReason = reason - - return fsm.state -} - -func (fsm *FSM) activate() { - fsm.eventCh <- ManualStart -} - -func (fsm *FSM) Stop() error { - fsm.eventCh <- ManualStop - fsm.t.Kill(nil) - return fsm.t.Wait() -} - -func (fsm *FSM) start() { - fsm.t.Go(fsm.main) - fsm.t.Go(fsm.tcpConnector) - return -} - -func (fsm *FSM) main() error { - next := fsm.idle() - for { - switch next { - case Cease: - fsm.t.Kill(fmt.Errorf("FSM is being stopped")) - return nil - case Idle: - next = fsm.idle() - case Connect: - next = fsm.connect() - case Active: - next = fsm.active() - case OpenSent: - next = fsm.openSent() - case OpenConfirm: - next = fsm.openConfirm() - case Established: - next = fsm.established() - } - } -} - -func (fsm *FSM) idle() int { - if fsm.adjRIBOut != nil { - fsm.rib.Unregister(fsm.adjRIBOut) - fsm.adjRIBOut.Unregister(fsm.updateSender) - } - fsm.adjRIBIn = nil - fsm.adjRIBOut = nil - for { - select { - case c := <-fsm.conCh: - c.Close() - continue - case e := <-fsm.eventCh: - reason := "" - switch e { - case ManualStart: - reason = "Received ManualStart event %d for %s peer" - case AutomaticStart: - reason = "Received AutomaticStart event %d for %s peer" - default: - continue - } - - fsm.connectRetryCounter = 0 - fsm.startConnectRetryTimer() - if fsm.passive { - return fsm.changeState(Active, fmt.Sprintf(reason, "passive")) - } - fsm.tcpConnect() - return fsm.changeState(Connect, fmt.Sprintf(reason, "active")) - } - - } -} - -func (fsm *FSM) tcpConnector() error { - for { - select { - case <-fsm.initiateCon: - c, err := net.DialTCP("tcp", &net.TCPAddr{IP: fsm.local}, &net.TCPAddr{IP: fsm.remote, Port: BGPPORT}) - if err != nil { - select { - case fsm.conErrCh <- err: - continue - case <-time.NewTimer(time.Second * 30).C: - continue - } - } - - select { - case fsm.conCh <- c: - continue - case <-time.NewTimer(time.Second * 30).C: - c.Close() - continue - } - case <-fsm.t.Dying(): - return nil - } - } -} - -func (fsm *FSM) tcpConnect() { - fsm.initiateCon <- struct{}{} -} - -// connect state waits for a TCP connection to be fully established. Either the active or passive one. -func (fsm *FSM) connect() int { - for { - select { - case e := <-fsm.eventCh: - if e == ManualStop { - fsm.connectRetryCounter = 0 - stopTimer(fsm.connectRetryTimer) - return fsm.changeState(Idle, "Manual stop event") - } - continue - case <-fsm.connectRetryTimer.C: - fsm.resetConnectRetryTimer() - fsm.tcpConnect() - continue - case c := <-fsm.conCh: - fsm.con = c - stopTimer(fsm.connectRetryTimer) - return fsm.connectSendOpen() - } - } -} - -func (fsm *FSM) connectSendOpen() int { - err := fsm.sendOpen(fsm.con) - if err != nil { - stopTimer(fsm.connectRetryTimer) - return fsm.changeState(Idle, fmt.Sprintf("Sending OPEN message failed: %v", err)) - } - fsm.holdTimer = time.NewTimer(time.Minute * 4) - return fsm.changeState(OpenSent, "Sent OPEN message") -} - -// in the active state we wait for a passive TCP connection to be established -func (fsm *FSM) active() int { - for { - select { - case e := <-fsm.eventCh: - if e == ManualStop { - fsm.disconnect() - fsm.connectRetryCounter = 0 - stopTimer(fsm.connectRetryTimer) - return fsm.changeState(Active, "Manual stop event") - } - continue - case <-fsm.connectRetryTimer.C: - fsm.resetConnectRetryTimer() - fsm.tcpConnect() - return fsm.changeState(Connect, "Connect retry timer expired") - case c := <-fsm.conCh: - fsm.con = c - stopTimer(fsm.connectRetryTimer) - return fsm.activeSendOpen() - } - } -} - -func (fsm *FSM) activeSendOpen() int { - err := fsm.sendOpen(fsm.con) - if err != nil { - fsm.resetConnectRetryTimer() - fsm.connectRetryCounter++ - return fsm.changeState(Idle, fmt.Sprintf("Sending OPEN message failed: %v", err)) - } - fsm.holdTimer = time.NewTimer(time.Minute * 4) - return fsm.changeState(OpenSent, "Sent OPEN message") -} - -func (fsm *FSM) msgReceiver(c *net.TCPConn) error { - for { - msg, err := recvMsg(c) - if err != nil { - fsm.msgRecvFailCh <- msgRecvErr{err: err, con: c} - return nil - - /*select { - case fsm.msgRecvFailCh <- msgRecvErr{err: err, con: c}: - continue - case <-time.NewTimer(time.Second * 60).C: - return nil - }*/ - } - fsm.msgRecvCh <- msgRecvMsg{msg: msg, con: c} - - select { - case <-fsm.stopMsgRecvCh: - return nil - default: - continue - } - } -} - -func (fsm *FSM) openSent() int { - go fsm.msgReceiver(fsm.con) - - for { - select { - case e := <-fsm.eventCh: - if e == ManualStop { - sendNotification(fsm.con, packet.Cease, 0) - stopTimer(fsm.connectRetryTimer) - fsm.disconnect() - fsm.connectRetryCounter = 0 - return fsm.changeState(Idle, "Manual stop event") - } - continue - case <-fsm.holdTimer.C: - sendNotification(fsm.con, packet.HoldTimeExpired, 0) - stopTimer(fsm.connectRetryTimer) - fsm.disconnect() - fsm.connectRetryCounter++ - return fsm.changeState(Idle, "Holdtimer expired") - case c := <-fsm.conCh: // 2nd connection coming in. Collision! - if fsm.con2 != nil { - log.WithFields(log.Fields{ - "peer": fsm.remote.String(), - "local": fsm.local.String(), - }).Warningf("Received third connection from peer. Dropping new connection") - c.Close() - continue - } - - err := fsm.sendOpen(c) // FIXME: Not sure if this is standard compliant - if err != nil { - c.Close() - continue - } - fsm.con2 = c - go fsm.msgReceiver(c) - continue - case recvMsg := <-fsm.msgRecvCh: - msg, err := packet.Decode(bytes.NewBuffer(recvMsg.msg)) - if err != nil { - switch bgperr := err.(type) { - case packet.BGPError: - sendNotification(fsm.con, bgperr.ErrorCode, bgperr.ErrorSubCode) - sendNotification(fsm.con2, bgperr.ErrorCode, bgperr.ErrorSubCode) - } - stopTimer(fsm.connectRetryTimer) - fsm.disconnect() - fsm.connectRetryCounter++ - return fsm.changeState(Idle, fmt.Sprintf("Failed to decode BGP message: %v", err)) - } - switch msg.Header.Type { - case packet.NotificationMsg: - nMsg := msg.Body.(*packet.BGPNotification) - if nMsg.ErrorCode == packet.UnsupportedVersionNumber { - stopTimer(fsm.connectRetryTimer) - fsm.disconnect() - return fsm.changeState(Idle, "Received NOTIFICATION") - } - - if nMsg.ErrorCode == packet.Cease { - // Was this connection to be closed anyways? - if fsm.dumpCon(recvMsg.con) { - continue - } - } - stopTimer(fsm.connectRetryTimer) - fsm.disconnect() - fsm.connectRetryCounter++ - return fsm.changeState(Idle, "Received NOTIFICATION") - case packet.OpenMsg: - openMsg := msg.Body.(*packet.BGPOpen) - fsm.neighborID = openMsg.BGPIdentifier - fsm.resolveCollision() - stopTimer(fsm.connectRetryTimer) - err := fsm.sendKeepalive() - if err != nil { - return fsm.openSentTCPFail(err) - } - fsm.holdTime = time.Duration(math.Min(float64(fsm.holdTimeConfigured), float64(openMsg.HoldTime))) - if fsm.holdTime != 0 { - fsm.holdTimer.Reset(time.Second * fsm.holdTime) - fsm.keepaliveTime = fsm.holdTime / 3 - if fsm.keepaliveTimer != nil { - fsm.keepaliveTimer.Stop() - } - fsm.keepaliveTimer = time.NewTicker(fsm.keepaliveTime * time.Second) - } - - fsm.processOpenOptions(openMsg.OptParams) - - return fsm.changeState(OpenConfirm, "Received OPEN message") - default: - sendNotification(fsm.con, packet.FiniteStateMachineError, 0) - stopTimer(fsm.connectRetryTimer) - fsm.con.Close() - fsm.connectRetryCounter++ - return fsm.changeState(Idle, "FSM Error") - } - case err := <-fsm.msgRecvFailCh: - if err.con == fsm.con && fsm.con2 != nil { - fsm.con.Close() - fsm.con = fsm.con2 - fsm.con2 = nil - continue - } - - if err.con == fsm.con2 { - fsm.con2.Close() - fsm.con2 = nil - continue - } - return fsm.openSentTCPFail(err.err) - } - } -} - -func (fsm *FSM) processOpenOptions(optParams []packet.OptParam) { - for _, optParam := range optParams { - if optParam.Type != packet.CapabilitiesParamType { - continue - } - - fsm.processCapabilities(optParam.Value.(packet.Capabilities)) - } -} - -func (fsm *FSM) processCapabilities(caps packet.Capabilities) { - for _, cap := range caps { - fsm.processCapability(cap) - } -} - -func (fsm *FSM) processCapability(cap packet.Capability) { - switch cap.Code { - case packet.AddPathCapabilityCode: - fsm.processAddPathCapability(cap.Value.(packet.AddPathCapability)) - - } -} - -func (fsm *FSM) processAddPathCapability(addPathCap packet.AddPathCapability) { - if addPathCap.AFI != 1 { - return - } - if addPathCap.SAFI != 1 { - return - } - switch addPathCap.SendReceive { - case packet.AddPathReceive: - if !fsm.peer.addPathSend.BestOnly { - fsm.capAddPathSend = true - } - case packet.AddPathSend: - if fsm.peer.addPathRecv { - fsm.capAddPathRecv = true - } - case packet.AddPathSendReceive: - if !fsm.peer.addPathSend.BestOnly { - fsm.capAddPathSend = true - } - if fsm.peer.addPathRecv { - fsm.capAddPathRecv = true - } - } -} - -func (fsm *FSM) openSentTCPFail(err error) int { - fsm.con.Close() - fsm.resetConnectRetryTimer() - return fsm.changeState(Active, fmt.Sprintf("TCP failure: %v", err)) -} - -func (fsm *FSM) dumpCon(c *net.TCPConn) bool { - p := fsm.isPassive(c) - if fsm.routerID > fsm.neighborID { - return p - } - return !p -} - -func (fsm *FSM) resolveCollision() { - if fsm.con2 == nil { - return - } - - if fsm.routerID > fsm.neighborID { - // Terminate passive connection - if fsm.isPassive(fsm.con) { - dumpCon(fsm.con) - fsm.con = fsm.con2 - return - } - if fsm.isPassive(fsm.con2) { - dumpCon(fsm.con2) - return - } - return - } - - // Terminate active connection - if !fsm.isPassive(fsm.con) { - dumpCon(fsm.con) - fsm.con = fsm.con2 - return - } - if !fsm.isPassive(fsm.con2) { - dumpCon(fsm.con2) - fsm.con2.Close() - fsm.con2 = nil - return - } -} - -func dumpCon(c *net.TCPConn) { - sendNotification(c, packet.Cease, packet.ConnectionCollisionResolution) - c.Close() -} - -func (fsm *FSM) isPassive(c *net.TCPConn) bool { - if c.LocalAddr().String() == fmt.Sprintf("%s:179", fsm.local.String()) { - return true - } - return false -} - -func (fsm *FSM) openConfirm() int { - for { - select { - case e := <-fsm.eventCh: - if e == ManualStop { // Event 2 - sendNotification(fsm.con, packet.Cease, 0) - stopTimer(fsm.connectRetryTimer) - fsm.disconnect() - fsm.connectRetryCounter = 0 - return fsm.changeState(Idle, "Manual stop event") - } - continue - case <-fsm.holdTimer.C: - sendNotification(fsm.con, packet.HoldTimeExpired, 0) - stopTimer(fsm.connectRetryTimer) - fsm.disconnect() - fsm.connectRetryCounter++ - return fsm.changeState(Idle, "Holdtimer expired") - case <-fsm.keepaliveTimer.C: - err := fsm.sendKeepalive() - if err != nil { - stopTimer(fsm.connectRetryTimer) - fsm.disconnect() - fsm.connectRetryCounter++ - return fsm.changeState(Idle, fmt.Sprintf("Failed to send keepalive: %v", err)) - } - continue - case c := <-fsm.conCh: - if fsm.con2 != nil { - log.WithFields(log.Fields{ - "peer": fsm.remote.String(), - "local": fsm.local.String(), - }).Warningf("Received third connection from peer. Dropping new connection") - c.Close() - continue - } - - err := fsm.sendOpen(c) // FIXME: Not sure if this is standard compliant - if err != nil { - c.Close() - continue - } - fsm.con2 = c - go fsm.msgReceiver(c) - continue - case recvMsg := <-fsm.msgRecvCh: - msg, err := packet.Decode(bytes.NewBuffer(recvMsg.msg)) - if err != nil { - log.WithError(err).Errorf("Failed to decode BGP message %v\n", recvMsg.msg) - switch bgperr := err.(type) { - case packet.BGPError: - sendNotification(fsm.con, bgperr.ErrorCode, bgperr.ErrorSubCode) - sendNotification(fsm.con2, bgperr.ErrorCode, bgperr.ErrorSubCode) - } - stopTimer(fsm.connectRetryTimer) - fsm.disconnect() - fsm.connectRetryCounter++ - return fsm.changeState(Idle, "Failed to decode BGP message") - } - - switch msg.Header.Type { - case packet.NotificationMsg: - nMsg := msg.Body.(*packet.BGPNotification) - if nMsg.ErrorCode == packet.UnsupportedVersionNumber { - stopTimer(fsm.connectRetryTimer) - fsm.con.Close() - return fsm.changeState(Idle, "Received NOTIFICATION") - } - - if nMsg.ErrorCode == packet.Cease { - // Was this connection to be closed anyways? - if fsm.dumpCon(recvMsg.con) { - continue - } - } - - return fsm.openConfirmTCPFail(fmt.Errorf("NOTIFICATION received")) - case packet.KeepaliveMsg: - fsm.holdTimer.Reset(time.Second * fsm.holdTime) - return fsm.changeState(Established, "Received KEEPALIVE") - case packet.OpenMsg: - openMsg := msg.Body.(*packet.BGPOpen) - fsm.neighborID = openMsg.BGPIdentifier - fsm.resolveCollision() - default: - sendNotification(fsm.con, packet.FiniteStateMachineError, 0) - stopTimer(fsm.connectRetryTimer) - fsm.con.Close() - fsm.connectRetryCounter++ - return fsm.changeState(Idle, "FSM Error") - } - case err := <-fsm.msgRecvFailCh: - if err.con == fsm.con && fsm.con2 != nil { - fsm.con.Close() - fsm.con = fsm.con2 - fsm.con2 = nil - continue - } - - if err.con == fsm.con2 { - fsm.con2.Close() - fsm.con2 = nil - continue - } - return fsm.openConfirmTCPFail(err.err) - } - } -} - -func (fsm *FSM) openConfirmTCPFail(err error) int { - fsm.con.Close() - fsm.resetConnectRetryTimer() - fsm.connectRetryCounter++ - return fsm.changeState(Idle, fmt.Sprintf("Failure: %v", err)) -} - -func (fsm *FSM) established() int { - fsm.adjRIBIn = adjRIBIn.New() - fsm.adjRIBIn.Register(fsm.rib) - - n := &routingtable.Neighbor{ - Type: route.BGPPathType, - Address: tnet.IPv4ToUint32(fsm.remote), - IBGP: fsm.remoteASN == fsm.localASN, - } - - clientOptions := routingtable.ClientOptions{ - BestOnly: true, - } - if fsm.capAddPathSend { - fsm.updateSender = newUpdateSenderAddPath(fsm) - fsm.adjRIBOut = adjRIBOutAddPath.New(n) - clientOptions = fsm.peer.addPathSend - } else { - fsm.updateSender = newUpdateSender(fsm) - fsm.adjRIBOut = adjRIBOut.New(n) - } - - fsm.adjRIBOut.Register(fsm.updateSender) - fsm.rib.RegisterWithOptions(fsm.adjRIBOut, clientOptions) - - /*go func() { - for { - if fsm.adjRIBOut == nil { - return - } - fmt.Printf("ADJ-RIB-OUT: %s\n", fsm.remote.String()) - fmt.Print(fsm.adjRIBOut.Print()) - time.Sleep(time.Second * 11) - } - }()*/ - - for { - log.Debug("Iterate established loop.") - select { - case e := <-fsm.eventCh: - if e == ManualStop { // Event 2 - sendNotification(fsm.con, packet.Cease, 0) - stopTimer(fsm.connectRetryTimer) - fsm.con.Close() - fsm.connectRetryCounter = 0 - return fsm.changeState(Idle, "Manual stop event") - } - if e == AutomaticStop { // Event 8 - sendNotification(fsm.con, packet.Cease, 0) - stopTimer(fsm.connectRetryTimer) - fsm.con.Close() - fsm.connectRetryCounter++ - return fsm.changeState(Idle, "Automatic stop event") - } - continue - case <-fsm.holdTimer.C: - sendNotification(fsm.con, packet.HoldTimeExpired, 0) - stopTimer(fsm.connectRetryTimer) - fsm.con.Close() - fsm.connectRetryCounter++ - return fsm.changeState(Idle, "Holdtimer expired") - case <-fsm.keepaliveTimer.C: - - err := fsm.sendKeepalive() - if err != nil { - stopTimer(fsm.connectRetryTimer) - fsm.con.Close() - fsm.connectRetryCounter++ - return fsm.changeState(Idle, fmt.Sprintf("Failed to send keepalive: %v", err)) - } - continue - case c := <-fsm.conCh: - c.Close() - continue - case recvMsg := <-fsm.msgRecvCh: - msg, err := packet.Decode(bytes.NewBuffer(recvMsg.msg)) - if err != nil { - log.WithError(err).Errorf("Failed to decode BGP message %v\n", recvMsg.msg) - switch bgperr := err.(type) { - case packet.BGPError: - sendNotification(fsm.con, bgperr.ErrorCode, bgperr.ErrorSubCode) - } - stopTimer(fsm.connectRetryTimer) - fsm.con.Close() - fsm.connectRetryCounter++ - return fsm.changeState(Idle, "Failed to decode BGP message") - } - switch msg.Header.Type { - case packet.NotificationMsg: - stopTimer(fsm.connectRetryTimer) - fsm.con.Close() - fsm.connectRetryCounter++ - return fsm.changeState(Idle, "Received NOTIFICATION") - case packet.UpdateMsg: - if fsm.holdTime != 0 { - fsm.holdTimer.Reset(time.Second * fsm.holdTime) - } - - u := msg.Body.(*packet.BGPUpdate) - - for r := u.WithdrawnRoutes; r != nil; r = r.Next { - pfx := tnet.NewPfx(r.IP, r.Pfxlen) - log.WithField("Prefix", pfx.String()).Debug("LPM: Removing prefix") - fsm.adjRIBIn.RemovePath(pfx, nil) - } - - for r := u.NLRI; r != nil; r = r.Next { - pfx := tnet.NewPfx(r.IP, r.Pfxlen) - log.WithField("Prefix", pfx.String()).Debug("LPM: Adding prefix") - path := &route.Path{ - Type: route.BGPPathType, - BGPPath: &route.BGPPath{ - Source: tnet.IPv4ToUint32(fsm.remote), - }, - } - - for pa := u.PathAttributes; pa != nil; pa = pa.Next { - switch pa.TypeCode { - case packet.OriginAttr: - path.BGPPath.Origin = pa.Value.(uint8) - case packet.LocalPrefAttr: - path.BGPPath.LocalPref = pa.Value.(uint32) - case packet.MEDAttr: - path.BGPPath.MED = pa.Value.(uint32) - case packet.NextHopAttr: - log.WithField("NextHop", pa.Value.(uint32)).Debug("RECEIVED NEXT_HOP") - path.BGPPath.NextHop = pa.Value.(uint32) - case packet.ASPathAttr: - path.BGPPath.ASPath = pa.ASPathString() - path.BGPPath.ASPathLen = pa.ASPathLen() - case packet.CommunitiesAttr: - path.BGPPath.Communities = pa.CommunityString() - case packet.LargeCommunitiesAttr: - path.BGPPath.LargeCommunities = pa.LargeCommunityString() - } - } - fsm.adjRIBIn.AddPath(pfx, path) - } - - continue - case packet.KeepaliveMsg: - if fsm.holdTime != 0 { - fsm.holdTimer.Reset(time.Second * fsm.holdTime) - } - continue - case packet.OpenMsg: - if fsm.con2 != nil { - sendNotification(fsm.con2, packet.Cease, packet.ConnectionCollisionResolution) - fsm.con2.Close() - fsm.con2 = nil - continue - } - sendNotification(fsm.con, packet.FiniteStateMachineError, 0) - stopTimer(fsm.connectRetryTimer) - fsm.con.Close() - fsm.connectRetryCounter++ - return fsm.changeState(Idle, "FSM Error") - default: - sendNotification(fsm.con, packet.FiniteStateMachineError, 0) - stopTimer(fsm.connectRetryTimer) - fsm.con.Close() - fsm.connectRetryCounter++ - return fsm.changeState(Idle, "FSM Error") - } - case err := <-fsm.msgRecvFailCh: - if err.con == fsm.con && fsm.con2 != nil { - fsm.con.Close() - fsm.con = fsm.con2 - fsm.con2 = nil - continue - } - - if err.con == fsm.con2 { - fsm.con2.Close() - fsm.con2 = nil - continue - } - return fsm.openConfirmTCPFail(err.err) - } - } -} - -func (fsm *FSM) startConnectRetryTimer() { - fsm.connectRetryTimer = time.NewTimer(time.Second * fsm.connectRetryTime) -} - -func (fsm *FSM) resetConnectRetryTimer() { - if !fsm.connectRetryTimer.Reset(time.Second * fsm.connectRetryTime) { - <-fsm.connectRetryTimer.C - } -} - -func (fsm *FSM) resetDelayOpenTimer() { - if !fsm.delayOpenTimer.Reset(time.Second * fsm.delayOpenTime) { - <-fsm.delayOpenTimer.C - } -} - -func (fsm *FSM) sendKeepalive() error { - - msg := packet.SerializeKeepaliveMsg() - _, err := fsm.con.Write(msg) - log.WithError(err).Debug("Send keepalive") - if err != nil { - return fmt.Errorf("Unable to send KEEPALIVE message: %v", err) - } - - return nil -} - -func (fsm *FSM) sendOpen(c *net.TCPConn) error { - msg := packet.SerializeOpenMsg(&packet.BGPOpen{ - Version: BGPVersion, - AS: fsm.localASN, - HoldTime: uint16(fsm.holdTimeConfigured), - BGPIdentifier: fsm.routerID, - OptParams: fsm.peer.optOpenParams, - }) - - _, err := c.Write(msg) - if err != nil { - return fmt.Errorf("Unable to send OPEN message: %v", err) - } - - return nil -} - -func sendNotification(c *net.TCPConn, errorCode uint8, errorSubCode uint8) error { - if c == nil { - return fmt.Errorf("connection is nil") - } - - msg := packet.SerializeNotificationMsg(&packet.BGPNotification{}) - - _, err := c.Write(msg) - if err != nil { - return fmt.Errorf("Unable to send NOTIFICATION message: %v", err) - } - - return nil -} diff --git a/protocols/bgp/server/fsm2.go b/protocols/bgp/server/fsm2.go index d0f4f15ff4d1fda7e6b1eb670ff85d51736ef794..86725c681f9a3c7c904d78c538380af4d758f1b0 100644 --- a/protocols/bgp/server/fsm2.go +++ b/protocols/bgp/server/fsm2.go @@ -8,7 +8,6 @@ import ( "github.com/bio-routing/bio-rd/protocols/bgp/packet" "github.com/bio-routing/bio-rd/routingtable" - "github.com/bio-routing/bio-rd/routingtable/locRIB" log "github.com/sirupsen/logrus" ) @@ -63,7 +62,7 @@ type FSM2 struct { ribsInitialized bool adjRIBIn routingtable.RouteTableClient adjRIBOut routingtable.RouteTableClient - rib *locRIB.LocRIB + rib routingtable.RouteTableClient updateSender routingtable.RouteTableClient neighborID uint32 diff --git a/protocols/bgp/server/peer.go b/protocols/bgp/server/peer.go index 8e9408a58fc0cdbb6f0c9f704877c9e145a0d449..6800ce16700218fbd01856e9f56c5f16a12e03fb 100644 --- a/protocols/bgp/server/peer.go +++ b/protocols/bgp/server/peer.go @@ -9,9 +9,6 @@ import ( "github.com/bio-routing/bio-rd/protocols/bgp/packet" "github.com/bio-routing/bio-rd/routingtable" "github.com/bio-routing/bio-rd/routingtable/filter" - "github.com/bio-routing/bio-rd/routingtable/locRIB" - - "time" ) type Peer struct { @@ -21,7 +18,7 @@ type Peer struct { localASN uint32 fsms []*FSM2 fsmsMu sync.Mutex - rib *locRIB.LocRIB + rib routingtable.RouteTableClient routerID uint32 addPathSend routingtable.ClientOptions addPathRecv bool @@ -85,7 +82,7 @@ func isEstablishedState(s state) bool { // NewPeer creates a new peer with the given config. If an connection is established, the adjRIBIN of the peer is connected // to the given rib. To actually connect the peer, call Start() on the returned peer. -func NewPeer(c config.Peer, rib *locRIB.LocRIB, server *BGPServer) (*Peer, error) { +func NewPeer(c config.Peer, rib routingtable.RouteTableClient, server *BGPServer) (*Peer, error) { p := &Peer{ server: server, addr: c.PeerAddress, diff --git a/protocols/bgp/server/update_sender.go b/protocols/bgp/server/update_sender.go index 6ba849d04938be4e19ea2ea22a083ea826896fa9..e087b7f256ccf05945b29ac715bffc167e723686 100644 --- a/protocols/bgp/server/update_sender.go +++ b/protocols/bgp/server/update_sender.go @@ -15,32 +15,20 @@ import ( // UpdateSender converts table changes into BGP update messages type UpdateSender struct { routingtable.ClientManager -<<<<<<< HEAD fsm *FSM2 iBGP bool -======= - fsm *FSM2 ->>>>>>> 453a853eeb0507c5e83706d9e3f251adba5b2484 } func newUpdateSender(fsm *FSM2) *UpdateSender { return &UpdateSender{ fsm: fsm, - iBGP: fsm.peer.localASN == fsm.peer.asn, + iBGP: fsm.peer.localASN == fsm.peer.peerASN, } } // AddPath serializes a new path and sends out a BGP update message func (u *UpdateSender) AddPath(pfx net.Prefix, p *route.Path) error { -<<<<<<< HEAD -<<<<<<< HEAD pathAttrs, err := pathAttribues(p, u.fsm) -======= - asPathPA, err := packet.ParseASPathStr(fmt.Sprintf("%d %s", u.fsm.peer.localASN, p.BGPPath.ASPath)) ->>>>>>> Replaced FSM -======= - asPathPA, err := packet.ParseASPathStr(fmt.Sprintf("%d %s", u.fsm.peer.localASN, p.BGPPath.ASPath)) ->>>>>>> 453a853eeb0507c5e83706d9e3f251adba5b2484 if err != nil { log.Errorf("Unable to create BGP Update: %v", err) return nil diff --git a/protocols/bgp/server/update_sender_add_path.go b/protocols/bgp/server/update_sender_add_path.go index edd36252888153dbed7d53c3a47704481b0eca66..e777180cb834361411fcef30f9ae8872ab0152e9 100644 --- a/protocols/bgp/server/update_sender_add_path.go +++ b/protocols/bgp/server/update_sender_add_path.go @@ -19,7 +19,7 @@ type UpdateSenderAddPath struct { func newUpdateSenderAddPath(fsm *FSM2) *UpdateSenderAddPath { return &UpdateSenderAddPath{ fsm: fsm, - iBGP: fsm.peer.localASN == fsm.peer.asn, + iBGP: fsm.peer.localASN == fsm.peer.peerASN, } }