func (fsm *FSM) sendNotificationFromErrorMsg(e *bgp.MessageError) error { if fsm.h != nil && fsm.h.conn != nil { m := bgp.NewBGPNotificationMessage(e.TypeCode, e.SubTypeCode, e.Data) b, _ := m.Serialize() _, err := fsm.h.conn.Write(b) if err == nil { fsm.bgpMessageStateUpdate(m.Header.Type, false) fsm.h.sentNotification = bgp.NewNotificationErrorCode(e.TypeCode, e.SubTypeCode).String() } fsm.h.conn.Close() log.WithFields(log.Fields{ "Topic": "Peer", "Key": fsm.pConf.Config.NeighborAddress, "Data": e, }).Warn("sent notification") return nil } return fmt.Errorf("can't send notification to %s since TCP connection is not established", fsm.pConf.Config.NeighborAddress) }
func (h *FSMHandler) recvMessageWithError() (*FsmMsg, error) { sendToErrorCh := func(reason FsmStateReason) { // probably doesn't happen but be cautious select { case h.errorCh <- reason: default: } } headerBuf, err := readAll(h.conn, bgp.BGP_HEADER_LENGTH) if err != nil { sendToErrorCh(FSM_READ_FAILED) return nil, err } hd := &bgp.BGPHeader{} err = hd.DecodeFromBytes(headerBuf) if err != nil { h.fsm.bgpMessageStateUpdate(0, true) log.WithFields(log.Fields{ "Topic": "Peer", "Key": h.fsm.pConf.Config.NeighborAddress, "State": h.fsm.state.String(), "error": err, }).Warn("malformed BGP Header") fmsg := &FsmMsg{ MsgType: FSM_MSG_BGP_MESSAGE, MsgSrc: h.fsm.pConf.Config.NeighborAddress, MsgData: err, Version: h.fsm.version, } return fmsg, err } bodyBuf, err := readAll(h.conn, int(hd.Len)-bgp.BGP_HEADER_LENGTH) if err != nil { sendToErrorCh(FSM_READ_FAILED) return nil, err } now := time.Now() m, err := bgp.ParseBGPBody(hd, bodyBuf) if err == nil { h.fsm.bgpMessageStateUpdate(m.Header.Type, true) err = bgp.ValidateBGPMessage(m) } else { h.fsm.bgpMessageStateUpdate(0, true) } fmsg := &FsmMsg{ MsgType: FSM_MSG_BGP_MESSAGE, MsgSrc: h.fsm.pConf.Config.NeighborAddress, timestamp: now, Version: h.fsm.version, } if err != nil { log.WithFields(log.Fields{ "Topic": "Peer", "Key": h.fsm.pConf.Config.NeighborAddress, "State": h.fsm.state.String(), "error": err, }).Warn("malformed BGP message") fmsg.MsgData = err } else { fmsg.MsgData = m if h.fsm.state == bgp.BGP_FSM_ESTABLISHED { switch m.Header.Type { case bgp.BGP_MSG_ROUTE_REFRESH: fmsg.MsgType = FSM_MSG_ROUTE_REFRESH case bgp.BGP_MSG_UPDATE: body := m.Body.(*bgp.BGPUpdate) confedCheck := !config.IsConfederationMember(h.fsm.gConf, h.fsm.pConf) && config.IsEBGPPeer(h.fsm.gConf, h.fsm.pConf) _, err := bgp.ValidateUpdateMsg(body, h.fsm.rfMap, confedCheck) if err != nil { log.WithFields(log.Fields{ "Topic": "Peer", "Key": h.fsm.pConf.Config.NeighborAddress, "State": h.fsm.state.String(), "error": err, }).Warn("malformed BGP update message") fmsg.MsgData = err } else { // FIXME: we should use the original message for bmp/mrt table.UpdatePathAttrs4ByteAs(body) err := table.UpdatePathAggregator4ByteAs(body) if err == nil { fmsg.PathList = table.ProcessMessage(m, h.fsm.peerInfo, fmsg.timestamp) id := h.fsm.pConf.Config.NeighborAddress for _, path := range fmsg.PathList { if path.IsEOR() { continue } if h.fsm.policy.ApplyPolicy(id, table.POLICY_DIRECTION_IN, path, nil) == nil { path.Filter(id, table.POLICY_DIRECTION_IN) } } } else { fmsg.MsgData = err } } fmsg.payload = make([]byte, len(headerBuf)+len(bodyBuf)) copy(fmsg.payload, headerBuf) copy(fmsg.payload[len(headerBuf):], bodyBuf) fallthrough case bgp.BGP_MSG_KEEPALIVE: // if the length of h.holdTimerResetCh // isn't zero, the timer will be reset // soon anyway. select { case h.holdTimerResetCh <- true: default: } if m.Header.Type == bgp.BGP_MSG_KEEPALIVE { return nil, nil } case bgp.BGP_MSG_NOTIFICATION: body := m.Body.(*bgp.BGPNotification) log.WithFields(log.Fields{ "Topic": "Peer", "Key": h.fsm.pConf.Config.NeighborAddress, "Code": body.ErrorCode, "Subcode": body.ErrorSubcode, "Data": body.Data, }).Warn("received notification") sendToErrorCh(FsmStateReason(fmt.Sprintf("%s %s", FSM_NOTIFICATION_RECV, bgp.NewNotificationErrorCode(body.ErrorCode, body.ErrorSubcode).String()))) return nil, nil } } } return fmsg, err }
func (h *FSMHandler) sendMessageloop() error { conn := h.conn fsm := h.fsm ticker := keepaliveTicker(fsm) send := func(m *bgp.BGPMessage) error { if fsm.twoByteAsTrans && m.Header.Type == bgp.BGP_MSG_UPDATE { log.WithFields(log.Fields{ "Topic": "Peer", "Key": fsm.pConf.Config.NeighborAddress, "State": fsm.state.String(), "Data": m, }).Debug("update for 2byte AS peer") table.UpdatePathAttrs2ByteAs(m.Body.(*bgp.BGPUpdate)) table.UpdatePathAggregator2ByteAs(m.Body.(*bgp.BGPUpdate)) } b, err := m.Serialize() if err != nil { log.WithFields(log.Fields{ "Topic": "Peer", "Key": fsm.pConf.Config.NeighborAddress, "State": fsm.state.String(), "Data": err, }).Warn("failed to serialize") fsm.bgpMessageStateUpdate(0, false) return nil } if err := conn.SetWriteDeadline(time.Now().Add(time.Second * time.Duration(fsm.pConf.Timers.State.NegotiatedHoldTime))); err != nil { h.errorCh <- FSM_WRITE_FAILED conn.Close() return fmt.Errorf("failed to set write deadline") } _, err = conn.Write(b) if err != nil { log.WithFields(log.Fields{ "Topic": "Peer", "Key": fsm.pConf.Config.NeighborAddress, "State": fsm.state.String(), "Data": err, }).Warn("failed to send") h.errorCh <- FSM_WRITE_FAILED conn.Close() return fmt.Errorf("closed") } fsm.bgpMessageStateUpdate(m.Header.Type, false) switch m.Header.Type { case bgp.BGP_MSG_NOTIFICATION: log.WithFields(log.Fields{ "Topic": "Peer", "Key": fsm.pConf.Config.NeighborAddress, "State": fsm.state.String(), "Data": m, }).Warn("sent notification") body := m.Body.(*bgp.BGPNotification) h.errorCh <- FsmStateReason(fmt.Sprintf("%s %s", FSM_NOTIFICATION_SENT, bgp.NewNotificationErrorCode(body.ErrorCode, body.ErrorSubcode).String())) conn.Close() return fmt.Errorf("closed") case bgp.BGP_MSG_UPDATE: update := m.Body.(*bgp.BGPUpdate) log.WithFields(log.Fields{ "Topic": "Peer", "Key": fsm.pConf.Config.NeighborAddress, "State": fsm.state.String(), "nlri": update.NLRI, "withdrawals": update.WithdrawnRoutes, "attributes": update.PathAttributes, }).Debug("sent update") default: log.WithFields(log.Fields{ "Topic": "Peer", "Key": fsm.pConf.Config.NeighborAddress, "State": fsm.state.String(), "data": m, }).Debug("sent") } return nil } for { select { case <-h.t.Dying(): return nil case o := <-h.outgoing.Out(): m := o.(*FsmOutgoingMsg) for _, msg := range table.CreateUpdateMsgFromPaths(m.Paths) { if err := send(msg); err != nil { return nil } } if m.Notification != nil { if m.StayIdle { // current user is only prefix-limit // fix me if this is not the case h.changeAdminState(ADMIN_STATE_PFX_CT) } if err := send(m.Notification); err != nil { return nil } } case <-ticker.C: if err := send(bgp.NewBGPKeepAliveMessage()); err != nil { return nil } } } }