func (c *BmpClient) Serve() { scanner := bufio.NewScanner(bufio.NewReader(c.conn)) scanner.Split(bgp.SplitBMP) for scanner.Scan() { msg, err := bgp.ParseBMPMessage(scanner.Bytes()) if err != nil { continue } if msg.Header.Type == bgp.BMP_MSG_ROUTE_MONITORING { bgpMsg := msg.Body.(*bgp.BMPRouteMonitoring).BGPUpdate if bgpMsg.Header.Type == bgp.BGP_MSG_UPDATE { update := bgpMsg.Body.(*bgp.BGPUpdate) table.UpdatePathAttrs4ByteAs(update) // TODO: drop non as attrs c.eventCh <- &BmpEvent{ EventType: BMP_EVENT_BGP_UPDATE, Data: update, } } } } log.Info("connection was closed,", c.conn.RemoteAddr()) c.eventCh <- &BmpEvent{ EventType: BMP_EVENT_DISCONNECTED, Conn: c.conn, } }
func (peer *Peer) handleBGPmessage(m *bgp.BGPMessage) ([]*table.Path, bool, []*bgp.BGPMessage) { bgpMsgList := []*bgp.BGPMessage{} pathList := []*table.Path{} log.WithFields(log.Fields{ "Topic": "Peer", "Key": peer.conf.NeighborConfig.NeighborAddress, "data": m, }).Debug("received") update := false switch m.Header.Type { case bgp.BGP_MSG_OPEN: peer.recvOpen = m body := m.Body.(*bgp.BGPOpen) peer.peerInfo.ID = m.Body.(*bgp.BGPOpen).ID r := make(map[bgp.RouteFamily]bool) for _, p := range body.OptParams { if paramCap, y := p.(*bgp.OptionParameterCapability); y { for _, c := range paramCap.Capability { m, ok := peer.capMap[c.Code()] if !ok { m = make([]bgp.ParameterCapabilityInterface, 0, 1) } peer.capMap[c.Code()] = append(m, c) if c.Code() == bgp.BGP_CAP_MULTIPROTOCOL { m := c.(*bgp.CapMultiProtocol) r[m.CapValue] = true } } } } for rf, _ := range peer.rfMap { if _, y := r[rf]; !y { delete(peer.rfMap, rf) } } // calculate HoldTime // RFC 4271 P.13 // a BGP speaker MUST calculate the value of the Hold Timer // by using the smaller of its configured Hold Time and the Hold Time // received in the OPEN message. holdTime := float64(body.HoldTime) myHoldTime := peer.conf.Timers.TimersConfig.HoldTime if holdTime > myHoldTime { peer.fsm.negotiatedHoldTime = myHoldTime } else { peer.fsm.negotiatedHoldTime = holdTime } case bgp.BGP_MSG_ROUTE_REFRESH: rr := m.Body.(*bgp.BGPRouteRefresh) rf := bgp.AfiSafiToRouteFamily(rr.AFI, rr.SAFI) if _, ok := peer.rfMap[rf]; !ok { log.WithFields(log.Fields{ "Topic": "Peer", "Key": peer.conf.NeighborConfig.NeighborAddress, "Data": rf, }).Warn("Route family isn't supported") break } if _, ok := peer.capMap[bgp.BGP_CAP_ROUTE_REFRESH]; ok { rfList := []bgp.RouteFamily{rf} peer.adjRib.DropOut(rfList) accepted, filtered := peer.getBestFromLocal(rfList) peer.adjRib.UpdateOut(accepted) pathList = append(pathList, accepted...) for _, path := range filtered { path.IsWithdraw = true pathList = append(pathList, path) } } else { log.WithFields(log.Fields{ "Topic": "Peer", "Key": peer.conf.NeighborConfig.NeighborAddress, }).Warn("ROUTE_REFRESH received but the capability wasn't advertised") } case bgp.BGP_MSG_UPDATE: update = true peer.conf.Timers.TimersState.UpdateRecvTime = time.Now().Unix() body := m.Body.(*bgp.BGPUpdate) confedCheckRequired := !peer.isConfederationMember && peer.isEBGPPeer() _, err := bgp.ValidateUpdateMsg(body, peer.rfMap, confedCheckRequired) if err != nil { log.WithFields(log.Fields{ "Topic": "Peer", "Key": peer.conf.NeighborConfig.NeighborAddress, "error": err, }).Warn("malformed BGP update message") m := err.(*bgp.MessageError) if m.TypeCode != 0 { bgpMsgList = append(bgpMsgList, bgp.NewBGPNotificationMessage(m.TypeCode, m.SubTypeCode, m.Data)) } break } table.UpdatePathAttrs4ByteAs(body) pathList = table.ProcessMessage(m, peer.peerInfo) if len(pathList) > 0 { peer.staleAccepted = true peer.ApplyPolicy(table.POLICY_DIRECTION_IN, pathList) peer.adjRib.UpdateIn(pathList) } case bgp.BGP_MSG_NOTIFICATION: body := m.Body.(*bgp.BGPNotification) log.WithFields(log.Fields{ "Topic": "Peer", "Key": peer.conf.NeighborConfig.NeighborAddress, "Code": body.ErrorCode, "Subcode": body.ErrorSubcode, "Data": body.Data, }).Warn("received notification") } return pathList, update, bgpMsgList }
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 (peer *Peer) handleBGPmessage(m *bgp.BGPMessage) ([]*table.Path, bool, []*bgp.BGPMessage) { bgpMsgList := []*bgp.BGPMessage{} pathList := []*table.Path{} log.WithFields(log.Fields{ "Topic": "Peer", "Key": peer.config.NeighborAddress, "data": m, }).Debug("received") update := false switch m.Header.Type { case bgp.BGP_MSG_OPEN: body := m.Body.(*bgp.BGPOpen) peer.peerInfo.ID = m.Body.(*bgp.BGPOpen).ID r := make(map[bgp.RouteFamily]bool) for _, p := range body.OptParams { if paramCap, y := p.(*bgp.OptionParameterCapability); y { for _, c := range paramCap.Capability { peer.capMap[c.Code()] = c if c.Code() == bgp.BGP_CAP_MULTIPROTOCOL { m := c.(*bgp.CapMultiProtocol) r[bgp.AfiSafiToRouteFamily(m.CapValue.AFI, m.CapValue.SAFI)] = true } } } } for rf, _ := range peer.rfMap { if _, y := r[rf]; !y { delete(peer.rfMap, rf) } } for _, rf := range peer.configuredRFlist() { if _, ok := r[rf]; ok { peer.rfMap[rf] = true } } // calculate HoldTime // RFC 4271 P.13 // a BGP speaker MUST calculate the value of the Hold Timer // by using the smaller of its configured Hold Time and the Hold Time // received in the OPEN message. holdTime := float64(body.HoldTime) myHoldTime := peer.config.Timers.HoldTime if holdTime > myHoldTime { peer.fsm.negotiatedHoldTime = myHoldTime } else { peer.fsm.negotiatedHoldTime = holdTime } case bgp.BGP_MSG_ROUTE_REFRESH: rr := m.Body.(*bgp.BGPRouteRefresh) rf := bgp.AfiSafiToRouteFamily(rr.AFI, rr.SAFI) if _, ok := peer.rfMap[rf]; !ok { log.WithFields(log.Fields{ "Topic": "Peer", "Key": peer.config.NeighborAddress, "Data": rf, }).Warn("Route family isn't supported") break } if _, ok := peer.capMap[bgp.BGP_CAP_ROUTE_REFRESH]; ok { pathList = peer.adjRib.GetOutPathList(rf) } else { log.WithFields(log.Fields{ "Topic": "Peer", "Key": peer.config.NeighborAddress, }).Warn("ROUTE_REFRESH received but the capability wasn't advertised") } case bgp.BGP_MSG_UPDATE: update = true peer.config.BgpNeighborCommonState.UpdateRecvTime = time.Now().Unix() body := m.Body.(*bgp.BGPUpdate) confedCheckRequired := !peer.isConfederationMember && peer.isEBGP _, err := bgp.ValidateUpdateMsg(body, peer.rfMap, confedCheckRequired) if err != nil { log.WithFields(log.Fields{ "Topic": "Peer", "Key": peer.config.NeighborAddress, "error": err, }).Warn("malformed BGP update message") m := err.(*bgp.MessageError) if m.TypeCode != 0 { bgpMsgList = append(bgpMsgList, bgp.NewBGPNotificationMessage(m.TypeCode, m.SubTypeCode, m.Data)) } break } table.UpdatePathAttrs4ByteAs(body) pathList = table.ProcessMessage(m, peer.peerInfo) peer.adjRib.UpdateIn(pathList) } return pathList, update, bgpMsgList }
func (h *FSMHandler) recvMessageWithError() error { headerBuf, err := readAll(h.conn, bgp.BGP_HEADER_LENGTH) if err != nil { h.errorCh <- true return 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.NeighborConfig.NeighborAddress, "State": h.fsm.state, "error": err, }).Warn("malformed BGP Header") h.msgCh <- &FsmMsg{ MsgType: FSM_MSG_BGP_MESSAGE, MsgSrc: h.fsm.pConf.NeighborConfig.NeighborAddress.String(), MsgDst: h.fsm.pConf.Transport.TransportConfig.LocalAddress.String(), MsgData: err, } return err } bodyBuf, err := readAll(h.conn, int(hd.Len)-bgp.BGP_HEADER_LENGTH) if err != nil { h.errorCh <- true return 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.NeighborConfig.NeighborAddress.String(), MsgDst: h.fsm.pConf.Transport.TransportConfig.LocalAddress.String(), timestamp: now, } if err != nil { log.WithFields(log.Fields{ "Topic": "Peer", "Key": h.fsm.pConf.NeighborConfig.NeighborAddress, "State": h.fsm.state, "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_UPDATE: body := m.Body.(*bgp.BGPUpdate) _, err := bgp.ValidateUpdateMsg(body, h.fsm.rfMap, h.fsm.confedCheck) if err != nil { log.WithFields(log.Fields{ "Topic": "Peer", "Key": h.fsm.pConf.NeighborConfig.NeighborAddress.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) fmsg.PathList = table.ProcessMessage(m, h.fsm.peerInfo, fmsg.timestamp) policyMutex.RLock() h.fsm.peer.ApplyPolicy(table.POLICY_DIRECTION_IN, fmsg.PathList) policyMutex.RUnlock() } 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 lenght of h.holdTimerResetCh // isn't zero, the timer will be reset // soon anyway. if len(h.holdTimerResetCh) == 0 { h.holdTimerResetCh <- true } case bgp.BGP_MSG_NOTIFICATION: h.reason = "Notification received" } } } h.msgCh <- fmsg return err }