gobgpd: support graceful-restart restarting-speaker behavior

use `-r` option to start gobgpd in restarting-speaker mode

Signed-off-by: ISHIDA Wataru <[email protected]>
This commit is contained in:
ISHIDA Wataru
2016-02-10 23:35:41 -08:00
committed by FUJITA Tomonori
parent a207c90fe4
commit b19bbd415e
7 changed files with 176 additions and 23 deletions
+10
View File
@@ -1709,6 +1709,12 @@ type MpGracefulRestartState struct {
// original -> bgp-op:advertised
//bgp-op:advertised's original type is boolean
Advertised bool `mapstructure:"advertised"`
// original -> gobgp:end-of-rib-received
//gobgp:end-of-rib-received's original type is boolean
EndOfRibReceived bool `mapstructure:"end-of-rib-received"`
// original -> gobgp:end-of-rib-sent
//gobgp:end-of-rib-sent's original type is boolean
EndOfRibSent bool `mapstructure:"end-of-rib-sent"`
}
//struct for container bgp-mp:config
@@ -1787,6 +1793,8 @@ type GracefulRestartState struct {
LocalRestarting bool `mapstructure:"local-restarting"`
// original -> bgp-op:mode
Mode Mode `mapstructure:"mode"`
// original -> gobgp:deferral-time
DeferralTime uint16 `mapstructure:"deferral-time"`
}
//struct for container bgp:config
@@ -1802,6 +1810,8 @@ type GracefulRestartConfig struct {
// original -> bgp:helper-only
//bgp:helper-only's original type is boolean
HelperOnly bool `mapstructure:"helper-only"`
// original -> gobgp:deferral-time
DeferralTime uint16 `mapstructure:"deferral-time"`
}
//struct for container bgp:graceful-restart
+7
View File
@@ -146,6 +146,13 @@ func SetDefaultConfigValues(v *viper.Viper, b *Bgp) error {
// equal to the HOLDTIME carried in the OPEN.
n.GracefulRestart.Config.RestartTime = uint16(n.Timers.Config.HoldTime)
}
if !vv.IsSet("neighbor.graceful-restart.config.deferral-time") {
// RFC 4724 4.1. Procedures for the Restarting Speaker
// The value of this timer should be large
// enough, so as to provide all the peers of the Restarting Speaker with
// enough time to send all the routes to the Restarting Speaker
n.GracefulRestart.Config.DeferralTime = uint16(360)
}
}
b.Neighbors[idx] = n
}
+18 -10
View File
@@ -38,16 +38,17 @@ func main() {
signal.Notify(sigCh, syscall.SIGHUP, syscall.SIGTERM)
var opts struct {
ConfigFile string `short:"f" long:"config-file" description:"specifying a config file"`
ConfigType string `short:"t" long:"config-type" description:"specifying config type (toml, yaml, json)" default:"toml"`
LogLevel string `short:"l" long:"log-level" description:"specifying log level"`
LogPlain bool `short:"p" long:"log-plain" description:"use plain format for logging (json by default)"`
UseSyslog string `short:"s" long:"syslog" description:"use syslogd"`
Facility string `long:"syslog-facility" description:"specify syslog facility"`
DisableStdlog bool `long:"disable-stdlog" description:"disable standard logging"`
CPUs int `long:"cpus" description:"specify the number of CPUs to be used"`
Ops bool `long:"openswitch" description:"openswitch mode"`
GrpcPort int `long:"grpc-port" description:"grpc port" default:"50051"`
ConfigFile string `short:"f" long:"config-file" description:"specifying a config file"`
ConfigType string `short:"t" long:"config-type" description:"specifying config type (toml, yaml, json)" default:"toml"`
LogLevel string `short:"l" long:"log-level" description:"specifying log level"`
LogPlain bool `short:"p" long:"log-plain" description:"use plain format for logging (json by default)"`
UseSyslog string `short:"s" long:"syslog" description:"use syslogd"`
Facility string `long:"syslog-facility" description:"specify syslog facility"`
DisableStdlog bool `long:"disable-stdlog" description:"disable standard logging"`
CPUs int `long:"cpus" description:"specify the number of CPUs to be used"`
Ops bool `long:"openswitch" description:"openswitch mode"`
GrpcPort int `short:"g" long:"grpc-port" description:"grpc port" default:"50051"`
GracefulRestart bool `short:"r" long:"graceful-restart" description:"flag restart-state in graceful-restart capability"`
}
_, err := flags.Parse(&opts)
if err != nil {
@@ -187,6 +188,13 @@ func main() {
bgpConfig = &newConfig.Bgp
bgpServer.SetRpkiConfig(newConfig.Bgp.RpkiServers)
added = newConfig.Bgp.Neighbors
if opts.GracefulRestart {
for i, n := range added {
if n.GracefulRestart.Config.Enabled {
added[i].GracefulRestart.State.LocalRestarting = true
}
}
}
deleted = []config.Neighbor{}
updated = []config.Neighbor{}
} else {
+1
View File
@@ -71,6 +71,7 @@ const (
REQ_BMP_NEIGHBORS
REQ_BMP_GLOBAL
REQ_BMP_ADJ_IN
REQ_DEFERRAL_TIMER_EXPIRED
)
type Server struct {
+15 -4
View File
@@ -138,13 +138,14 @@ func (peer *Peer) getBestFromLocal(rfList []bgp.RouteFamily) ([]*table.Path, []*
return pathList, filtered
}
func (peer *Peer) handleBGPmessage(e *FsmMsg) ([]*table.Path, []*bgp.BGPMessage) {
func (peer *Peer) handleBGPmessage(e *FsmMsg) ([]*table.Path, []*bgp.BGPMessage, []bgp.RouteFamily) {
m := e.MsgData.(*bgp.BGPMessage)
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": peer.conf.Config.NeighborAddress,
"data": m,
}).Debug("received")
eor := []bgp.RouteFamily{}
switch m.Header.Type {
case bgp.BGP_MSG_ROUTE_REFRESH:
@@ -167,7 +168,7 @@ func (peer *Peer) handleBGPmessage(e *FsmMsg) ([]*table.Path, []*bgp.BGPMessage)
path.IsWithdraw = true
accepted = append(accepted, path)
}
return nil, table.CreateUpdateMsgFromPaths(accepted)
return nil, table.CreateUpdateMsgFromPaths(accepted), eor
} else {
log.WithFields(log.Fields{
"Topic": "Peer",
@@ -181,14 +182,24 @@ func (peer *Peer) handleBGPmessage(e *FsmMsg) ([]*table.Path, []*bgp.BGPMessage)
peer.adjRibIn.Update(e.PathList)
paths := make([]*table.Path, 0, len(e.PathList))
for _, path := range e.PathList {
if path.IsEOR() {
family := path.GetRouteFamily()
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": peer.conf.Config.NeighborAddress,
"AddressFamily": family,
}).Debug("EOR received")
eor = append(eor, family)
continue
}
if path.Filtered(peer.ID()) != table.POLICY_DIRECTION_IN {
paths = append(paths, path)
}
}
return paths, nil
return paths, nil, eor
}
}
return nil, nil
return nil, nil, eor
}
func (peer *Peer) startFSMHandler(incoming, stateCh chan *FsmMsg) {
+99 -9
View File
@@ -874,7 +874,7 @@ func (server *BgpServer) propagateUpdate(peer *Peer, pathList []*table.Path) ([]
dsts := rib.ProcessPaths(append(pathList, moded...))
server.validatePaths(dsts, false)
for _, targetPeer := range server.neighborMap {
if !targetPeer.isRouteServerClient() || targetPeer.fsm.state != bgp.BGP_FSM_ESTABLISHED {
if !targetPeer.isRouteServerClient() || targetPeer.fsm.state != bgp.BGP_FSM_ESTABLISHED || targetPeer.fsm.pConf.GracefulRestart.State.LocalRestarting {
continue
}
sendPathList := make([]*table.Path, 0, len(dsts))
@@ -913,7 +913,13 @@ func (server *BgpServer) propagateUpdate(peer *Peer, pathList []*table.Path) ([]
}
for _, targetPeer := range server.neighborMap {
if targetPeer.isRouteServerClient() || targetPeer.fsm.state != bgp.BGP_FSM_ESTABLISHED {
if targetPeer.isRouteServerClient() || targetPeer.fsm.state != bgp.BGP_FSM_ESTABLISHED || targetPeer.fsm.pConf.GracefulRestart.State.LocalRestarting {
if targetPeer.fsm.pConf.GracefulRestart.State.LocalRestarting {
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": targetPeer.conf.Config.NeighborAddress,
}).Debug("now syncing, suppress sending updates")
}
continue
}
pathList := make([]*table.Path, len(sendPathList))
@@ -963,10 +969,29 @@ func (server *BgpServer) handleFSMMessage(peer *Peer, e *FsmMsg) []*SenderMsg {
// update for export policy
laddr, _ := peer.fsm.LocalHostPort()
peer.conf.Transport.Config.LocalAddress = laddr
pathList, _ := peer.getBestFromLocal(peer.configuredRFlist())
if len(pathList) > 0 {
peer.adjRibOut.Update(pathList)
msgs = append(msgs, newSenderMsg(peer, table.CreateUpdateMsgFromPaths(pathList)))
if !peer.fsm.pConf.GracefulRestart.State.LocalRestarting {
pathList, _ := peer.getBestFromLocal(peer.configuredRFlist())
if len(pathList) > 0 {
peer.adjRibOut.Update(pathList)
msgs = append(msgs, newSenderMsg(peer, table.CreateUpdateMsgFromPaths(pathList)))
}
} else {
// RFC 4724 4.1
// Once the session between the Restarting Speaker and the Receiving
// Speaker is re-established, the Restarting Speaker will receive and
// process BGP messages from its peers. However, it MUST defer route
// selection for an address family until it either (a) ...snip...
// or (b) the Selection_Deferral_Timer referred to below has expired.
deferral := peer.fsm.pConf.GracefulRestart.Config.DeferralTime
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": peer.conf.Config.NeighborAddress,
}).Debugf("now syncing, suppress sending updates. start deferral timer(%d)", deferral)
time.AfterFunc(time.Second*time.Duration(deferral), func() {
req := NewGrpcRequest(REQ_DEFERRAL_TIMER_EXPIRED, peer.conf.Config.NeighborAddress, bgp.RouteFamily(0), nil)
server.GrpcReqCh <- req
<-req.ResponseCh
})
}
} else {
if server.shutdown && nextState == bgp.BGP_FSM_IDLE {
@@ -996,7 +1021,7 @@ func (server *BgpServer) handleFSMMessage(peer *Peer, e *FsmMsg) []*SenderMsg {
case *bgp.MessageError:
msgs = append(msgs, newSenderMsg(peer, []*bgp.BGPMessage{bgp.NewBGPNotificationMessage(m.TypeCode, m.SubTypeCode, m.Data)}))
case *bgp.BGPMessage:
pathList, msgList := peer.handleBGPmessage(e)
pathList, msgList, eor := peer.handleBGPmessage(e)
if m.Header.Type == bgp.BGP_MSG_UPDATE && server.watchers.watching(WATCHER_EVENT_UPDATE_MSG) {
_, y := peer.fsm.capMap[bgp.BGP_CAP_FOUR_OCTET_AS_NUMBER]
@@ -1045,6 +1070,58 @@ func (server *BgpServer) handleFSMMessage(peer *Peer, e *FsmMsg) []*SenderMsg {
}
}
}
if len(eor) > 0 {
// RFC 4724 4.1
// Once the session between the Restarting Speaker and the Receiving
// Speaker is re-established, ...snip... it MUST defer route
// selection for an address family until it either (a) receives the
// End-of-RIB marker from all its peers (excluding the ones with the
// "Restart State" bit set in the received capability and excluding the
// ones that do not advertise the graceful restart capability) or ...snip...
if peer.fsm.pConf.GracefulRestart.State.LocalRestarting {
var end bool
for _, f := range eor {
end = true
for i, a := range peer.fsm.pConf.AfiSafis {
if g, _ := bgp.GetRouteFamily(string(a.AfiSafiName)); f == g {
peer.fsm.pConf.AfiSafis[i].MpGracefulRestart.State.EndOfRibReceived = true
}
if s := a.MpGracefulRestart.State; s.Enabled && !s.EndOfRibReceived {
end = false
}
}
}
if end {
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": peer.conf.Config.NeighborAddress,
}).Debug("all family's EOR received")
peer.fsm.pConf.GracefulRestart.State.LocalRestarting = false
}
allEnd := true
for _, p := range server.neighborMap {
if p.fsm.pConf.GracefulRestart.State.LocalRestarting {
allEnd = false
}
}
if allEnd {
for _, p := range server.neighborMap {
if !p.isGracefulRestartEnabled() {
continue
}
pathList, _ := p.getBestFromLocal(p.configuredRFlist())
if len(pathList) > 0 {
p.adjRibOut.Update(pathList)
msgs = append(msgs, newSenderMsg(p, table.CreateUpdateMsgFromPaths(pathList)))
}
}
log.WithFields(log.Fields{
"Topic": "Server",
}).Info("sync finished")
}
}
}
default:
log.WithFields(log.Fields{
"Topic": "Peer",
@@ -1942,7 +2019,7 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg {
break
}
fallthrough
case REQ_NEIGHBOR_SOFT_RESET_OUT:
case REQ_NEIGHBOR_SOFT_RESET_OUT, REQ_DEFERRAL_TIMER_EXPIRED:
peers, err := reqToPeers(grpcReq)
if err != nil {
break
@@ -1954,6 +2031,19 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg {
if peer.fsm.state != bgp.BGP_FSM_ESTABLISHED {
continue
}
if grpcReq.RequestType == REQ_DEFERRAL_TIMER_EXPIRED {
if peer.fsm.pConf.GracefulRestart.State.LocalRestarting {
peer.fsm.pConf.GracefulRestart.State.LocalRestarting = false
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": peer.conf.Config.NeighborAddress,
}).Debug("deferral timer expired")
} else {
continue
}
}
families := []bgp.RouteFamily{grpcReq.RouteFamily}
if families[0] == bgp.RouteFamily(0) {
families = peer.configuredRFlist()
@@ -1965,7 +2055,7 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg {
peer.adjRibOut.Update(pathList)
msgs = append(msgs, newSenderMsg(peer, table.CreateUpdateMsgFromPaths(pathList)))
}
if len(filtered) > 0 {
if grpcReq.RequestType != REQ_DEFERRAL_TIMER_EXPIRED && len(filtered) > 0 {
withdrawnList := make([]*table.Path, 0, len(filtered))
for _, p := range filtered {
found := false
+26
View File
@@ -10,6 +10,7 @@ module gobgp {
// import some basic types
import openconfig-bgp { prefix bgp; }
import openconfig-bgp-types { prefix bgp-types; }
import openconfig-bgp-multiprotocol { prefix bgp-mp; }
import openconfig-routing-policy {prefix rpol; }
import openconfig-policy-types {prefix ptypes; }
import openconfig-bgp-policy {prefix bgp-pol; }
@@ -572,6 +573,30 @@ module gobgp {
uses gobgp-neighbor-timer;
}
augment "/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:afi-safis/bgp:afi-safi/bgp:graceful-restart/bgp:state" {
description "additional graceful-restart status";
leaf end-of-rib-received {
type boolean;
}
leaf end-of-rib-sent {
type boolean;
}
}
augment "/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:graceful-restart/bgp:config" {
description "additional graceful-restart status";
leaf deferral-time {
type uint16;
}
}
augment "/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:graceful-restart/bgp:state" {
description "additional graceful-restart status";
leaf deferral-time {
type uint16;
}
}
augment "/bgp:bgp/bgp:peer-groups/bgp:peer-group" {
description "route server configuration for peer-group";
uses gobgp-route-server-config-set;
@@ -742,4 +767,5 @@ module gobgp {
}
}
}
}