summaryrefslogtreecommitdiffhomepage
path: root/server
diff options
context:
space:
mode:
authorSatoshi Fujimoto <satoshi.fujimoto7@gmail.com>2017-08-03 10:44:27 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2017-09-29 15:05:43 +0900
commitf70827b68c190e3793ace65f116fef8c7c36e752 (patch)
tree52b1132afb0bbb4336e92b1d20eaa08150030e2e /server
parente2e8a840e67868cc3070530fe5e1a0dc3edf73f1 (diff)
server: Revised Error Handling (RFC7606)
This patch enables GoBGP to keep the session established even if the received BGPUpdate message contains some errors, and to handle these errors according to what defined in RFC7606. This feature is enabled when 'treat-as-withdraw' in 'neighbors.error-handling.config' is specified to true in the GoBGP config file. Signed-off-by: Satoshi Fujimoto <satoshi.fujimoto7@gmail.com>
Diffstat (limited to 'server')
-rw-r--r--server/fsm.go122
1 files changed, 111 insertions, 11 deletions
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 {