diff options
-rw-r--r-- | packet/bgp/bgp.go | 25 | ||||
-rw-r--r-- | server/fsm.go | 122 |
2 files changed, 136 insertions, 11 deletions
diff --git a/packet/bgp/bgp.go b/packet/bgp/bgp.go index 7e60b96e..fb9e2a1c 100644 --- a/packet/bgp/bgp.go +++ b/packet/bgp/bgp.go @@ -7982,6 +7982,31 @@ func (msg *BGPUpdate) IsEndOfRib() (bool, RouteFamily) { return false, RouteFamily(0) } +func TreatAsWithdraw(msg *BGPUpdate) *BGPUpdate { + withdraw := &BGPUpdate{ + WithdrawnRoutesLen: 0, + WithdrawnRoutes: []*IPAddrPrefix{}, + TotalPathAttributeLen: 0, + PathAttributes: make([]PathAttributeInterface, 0, len(msg.PathAttributes)), + NLRI: []*IPAddrPrefix{}, + } + withdraw.WithdrawnRoutes = append(msg.WithdrawnRoutes, msg.NLRI...) + var unreach []AddrPrefixInterface + + for _, p := range msg.PathAttributes { + switch nlri := p.(type) { + case *PathAttributeMpReachNLRI: + unreach = append(unreach, nlri.Value...) + case *PathAttributeMpUnreachNLRI: + unreach = append(unreach, nlri.Value...) + } + } + if len(unreach) != 0 { + withdraw.PathAttributes = append(withdraw.PathAttributes, NewPathAttributeMpUnreachNLRI(unreach)) + } + return withdraw +} + func NewBGPUpdateMessage(withdrawnRoutes []*IPAddrPrefix, pathattrs []PathAttributeInterface, nlri []*IPAddrPrefix) *BGPMessage { return &BGPMessage{ Header: BGPHeader{Type: BGP_MSG_UPDATE}, diff --git a/server/fsm.go b/server/fsm.go index df31b30b..0d208eb4 100644 --- a/server/fsm.go +++ b/server/fsm.go @@ -681,6 +681,92 @@ func hasOwnASLoop(ownAS uint32, limit int, aspath *bgp.PathAttributeAsPath) bool return false } +func extractRouteFamily(p *bgp.PathAttributeInterface) *bgp.RouteFamily { + attr := *p + + var afi uint16 + var safi uint8 + + switch a := attr.(type) { + case *bgp.PathAttributeMpReachNLRI: + afi = a.AFI + safi = a.SAFI + case *bgp.PathAttributeMpUnreachNLRI: + afi = a.AFI + safi = a.SAFI + default: + return nil + } + + rf := bgp.AfiSafiToRouteFamily(afi, safi) + return &rf +} + +func (h *FSMHandler) afiSafiDisable(rf bgp.RouteFamily) string { + n := bgp.AddressFamilyNameMap[rf] + + for i, a := range h.fsm.pConf.AfiSafis { + if string(a.Config.AfiSafiName) == n { + h.fsm.pConf.AfiSafis[i].State.Enabled = false + break + } + } + newList := make([]bgp.ParameterCapabilityInterface, 0) + for _, c := range h.fsm.capMap[bgp.BGP_CAP_MULTIPROTOCOL] { + if c.(*bgp.CapMultiProtocol).CapValue == rf { + continue + } + newList = append(newList, c) + } + h.fsm.capMap[bgp.BGP_CAP_MULTIPROTOCOL] = newList + return n +} + +func (h *FSMHandler) handlingError(m *bgp.BGPMessage, e error, useRevisedError bool) bgp.ErrorHandling { + handling := bgp.ERROR_HANDLING_NONE + if m.Header.Type == bgp.BGP_MSG_UPDATE && useRevisedError { + factor := e.(*bgp.MessageError) + handling = factor.ErrorHandling + switch handling { + case bgp.ERROR_HANDLING_ATTRIBUTE_DISCARD: + log.WithFields(log.Fields{ + "Topic": "Peer", + "Key": h.fsm.pConf.State.NeighborAddress, + "State": h.fsm.state.String(), + "error": e, + }).Warn("Some attributes were discarded") + case bgp.ERROR_HANDLING_TREAT_AS_WITHDRAW: + m.Body = bgp.TreatAsWithdraw(m.Body.(*bgp.BGPUpdate)) + log.WithFields(log.Fields{ + "Topic": "Peer", + "Key": h.fsm.pConf.State.NeighborAddress, + "State": h.fsm.state.String(), + "error": e, + }).Warn("the received Update message was treated as withdraw") + case bgp.ERROR_HANDLING_AFISAFI_DISABLE: + rf := extractRouteFamily(factor.ErrorAttribute) + if rf == nil { + log.WithFields(log.Fields{ + "Topic": "Peer", + "Key": h.fsm.pConf.State.NeighborAddress, + "State": h.fsm.state.String(), + }).Warn("Error occured during AFI/SAFI disabling") + } else { + n := h.afiSafiDisable(*rf) + log.WithFields(log.Fields{ + "Topic": "Peer", + "Key": h.fsm.pConf.State.NeighborAddress, + "State": h.fsm.state.String(), + "error": e, + }).Warnf("Capability %s was disabled", n) + } + } + } else { + handling = bgp.ERROR_HANDLING_SESSION_RESET + } + return handling +} + func (h *FSMHandler) recvMessageWithError() (*FsmMsg, error) { sendToErrorCh := func(reason FsmStateReason) { // probably doesn't happen but be cautious @@ -705,7 +791,7 @@ func (h *FSMHandler) recvMessageWithError() (*FsmMsg, error) { "Key": h.fsm.pConf.State.NeighborAddress, "State": h.fsm.state.String(), "error": err, - }).Warn("malformed BGP Header") + }).Warn("Session will be reset due to malformed BGP Header") fmsg := &FsmMsg{ MsgType: FSM_MSG_BGP_MESSAGE, MsgSrc: h.fsm.pConf.State.NeighborAddress, @@ -722,12 +808,16 @@ func (h *FSMHandler) recvMessageWithError() (*FsmMsg, error) { } now := time.Now() + useRevisedError := h.fsm.pConf.ErrorHandling.Config.TreatAsWithdraw + handling := bgp.ERROR_HANDLING_NONE + m, err := bgp.ParseBGPBody(hd, bodyBuf, h.fsm.marshallingOptions) - if err == nil { + if err != nil { + handling = h.handlingError(m, err, useRevisedError) + h.fsm.bgpMessageStateUpdate(0, true) + } else { h.fsm.bgpMessageStateUpdate(m.Header.Type, true) err = bgp.ValidateBGPMessage(m) - } else { - h.fsm.bgpMessageStateUpdate(0, true) } fmsg := &FsmMsg{ MsgType: FSM_MSG_BGP_MESSAGE, @@ -735,15 +825,21 @@ func (h *FSMHandler) recvMessageWithError() (*FsmMsg, error) { timestamp: now, Version: h.fsm.version, } - if err != nil { + + switch handling { + case bgp.ERROR_HANDLING_AFISAFI_DISABLE: + fmsg.MsgData = m + return fmsg, nil + case bgp.ERROR_HANDLING_SESSION_RESET: log.WithFields(log.Fields{ "Topic": "Peer", "Key": h.fsm.pConf.State.NeighborAddress, "State": h.fsm.state.String(), "error": err, - }).Warn("malformed BGP message") + }).Warn("Session will be reset due to malformed BGP message") fmsg.MsgData = err - } else { + return fmsg, err + default: fmsg.MsgData = m if h.fsm.state == bgp.BGP_FSM_ESTABLISHED { switch m.Header.Type { @@ -757,14 +853,18 @@ func (h *FSMHandler) recvMessageWithError() (*FsmMsg, error) { copy(fmsg.payload, headerBuf) copy(fmsg.payload[len(headerBuf):], bodyBuf) - _, err = bgp.ValidateUpdateMsg(body, h.fsm.rfMap, confedCheck) - if err != nil { + ok, err := bgp.ValidateUpdateMsg(body, h.fsm.rfMap, confedCheck) + if !ok { + handling = h.handlingError(m, err, useRevisedError) + } + + if handling == bgp.ERROR_HANDLING_SESSION_RESET { log.WithFields(log.Fields{ "Topic": "Peer", "Key": h.fsm.pConf.State.NeighborAddress, "State": h.fsm.state.String(), "error": err, - }).Warn("malformed BGP update message") + }).Warn("Session will be reset due to malformed BGP update message") fmsg.MsgData = err return fmsg, err } @@ -848,7 +948,7 @@ func (h *FSMHandler) recvMessageWithError() (*FsmMsg, error) { } } } - return fmsg, err + return fmsg, nil } func (h *FSMHandler) recvMessage() error { |