Skip to content

Commit

Permalink
Sending Cease/Hard Reset notification
Browse files Browse the repository at this point in the history
Send Cease/Hard Reset notification for certain scenario when graceful
restart + notification support (RFC8538) are enabled. In this
implementation, we follow the suggestion of RFC8538 and map following
notification subcodes to Hard Reset subcode.

1. BGP_ERROR_SUB_MAXIMUM_NUMBER_OF_PREFIXES_REACHED

In this case, GoBGP is in the resource shortage and not working
properly. Thus, the peer should stop forwarding packet immediately.

2. BGP_ERROR_SUB_ADMINISTRATIVE_SHUTDOWN

This happens when the user uses DisablePeer API. This clearly indicates
user's intention of shutting down the session. Thus, we should send Hard
Reset.

3. BGP_ERROR_SUB_PEER_DECONFIGURED

This happens whne the user uses DeletePeer API or StopBgp API or there's
an ASN mismatch found in the Open phase. The former two cases, the user
shows the intention to shutdown the session, so we should Hard Reset.
The latter case is not so obvious, but I think it's ok to do Hard Reset
because it is an unrecoverable error that cannot be solved without
user's involvement.

4. Hard Reset

This case currently doesn't exist, but obviously we should send Hard
Reset when someone explicitly specifies it.

The behavior for the remaining subcodes are unchanged. We may want to
expose a knob to adjust the behavior of BGP_ERROR_SUB_ADMINISTRATIVE_RESET
as suggested by RFC8538, but for this initial implementation, we kept it
as is.

Signed-off-by: Yutaro Hayakawa <[email protected]>
  • Loading branch information
YutaroHayakawa committed Apr 27, 2024
1 parent 7ef2f0b commit 621b312
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 0 deletions.
28 changes: 28 additions & 0 deletions pkg/packet/bgp/bgp.go
Original file line number Diff line number Diff line change
Expand Up @@ -14647,6 +14647,34 @@ func NewBGPNotificationMessage(errcode uint8, errsubcode uint8, data []byte) *BG
}
}

// RFC8538 makes a suggestion that which Cease notification subcodes should be
// mapped to the Hard Reset. This function takes a subcode and returns true if
// the subcode should be treated as a Hard Reset. Otherwise, it returns false.
//
// The second argument is a boolean value that indicates whether the Hard Reset
// should be performed on the Admin Reset. This reflects the RFC8538's
// suggestion that the implementation should provide a control to treat the
// Admin Reset as a Hard Reset. When the second argument is true, the function
// returns true if the subcode is BGP_ERROR_SUB_ADMINISTRATIVE_RESET.
// Otherwise, it returns false.
//
// As RFC8538 states, it is not mandatory to follow this suggestion. You can
// use this function when you want to follow the suggestion.
func ShouldHardReset(subcode uint8, hardResetOnAdminReset bool) bool {
switch subcode {
case BGP_ERROR_SUB_MAXIMUM_NUMBER_OF_PREFIXES_REACHED,
BGP_ERROR_SUB_ADMINISTRATIVE_SHUTDOWN,
BGP_ERROR_SUB_PEER_DECONFIGURED,
BGP_ERROR_SUB_HARD_RESET:
return true
default:
if hardResetOnAdminReset && subcode == BGP_ERROR_SUB_ADMINISTRATIVE_RESET {
return true
}
return false
}
}

type BGPKeepAlive struct {
}

Expand Down
17 changes: 17 additions & 0 deletions pkg/server/fsm.go
Original file line number Diff line number Diff line change
Expand Up @@ -1659,6 +1659,23 @@ func (h *fsmHandler) sendMessageloop(ctx context.Context, wg *sync.WaitGroup) er
table.UpdatePathAttrs2ByteAs(m.Body.(*bgp.BGPUpdate))
table.UpdatePathAggregator2ByteAs(m.Body.(*bgp.BGPUpdate))
}

// RFC8538 defines a Hard Reset notification subcode which
// indicates that the BGP speaker wants to reset the session
// without triggering graceful restart procedures. Here we map
// notification subcodes to the Hard Reset subcode following
// the RFC8538 suggestion.
//
// We check Status instead of Config because RFC8538 states
// that A BGP speaker SHOULD NOT send a Hard Reset to a peer
// from which it has not received the "N" bit.
if fsm.pConf.GracefulRestart.State.NotificationEnabled && m.Header.Type == bgp.BGP_MSG_NOTIFICATION {
body := m.Body.(*bgp.BGPNotification)
if body.ErrorCode == bgp.BGP_ERROR_CEASE && bgp.ShouldHardReset(body.ErrorSubcode, false) {
body.ErrorSubcode = bgp.BGP_ERROR_SUB_HARD_RESET
}
}

b, err := m.Serialize(h.fsm.marshallingOptions)
fsm.lock.RUnlock()
if err != nil {
Expand Down

0 comments on commit 621b312

Please sign in to comment.