summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--docs/sources/configuration.md3
-rw-r--r--gobgp/cmd/neighbor.go5
-rw-r--r--server/fsm.go16
-rw-r--r--server/peer.go48
-rw-r--r--server/server.go7
-rw-r--r--test/lib/base.py5
-rw-r--r--test/lib/gobgp.py4
-rw-r--r--test/scenario_test/route_server_test.py2
8 files changed, 65 insertions, 25 deletions
diff --git a/docs/sources/configuration.md b/docs/sources/configuration.md
index 89aa2c2c..72c527a3 100644
--- a/docs/sources/configuration.md
+++ b/docs/sources/configuration.md
@@ -64,6 +64,9 @@
route-reflector-cluster-id = "192.168.0.1"
[[neighbors.afi-safis]]
afi-safi-name = "ipv4-unicast"
+ [neighbors.afi-safis.prefix-limit.config]
+ max-prefixes = 1000
+ shutdown-threshold-pct = 80
[[neighbors.afi-safis]]
afi-safi-name = "ipv6-unicast"
[[neighbors.afi-safis]]
diff --git a/gobgp/cmd/neighbor.go b/gobgp/cmd/neighbor.go
index f20f7c88..bd6f3a1a 100644
--- a/gobgp/cmd/neighbor.go
+++ b/gobgp/cmd/neighbor.go
@@ -113,8 +113,11 @@ func showNeighbors() error {
format += " %-11s |%11s %8s %8s\n"
fmt.Printf(format, "Peer", "AS", "Up/Down", "State", "#Advertised", "Received", "Accepted")
format_fsm := func(admin, fsm string) string {
- if admin == "ADMIN_STATE_DOWN" {
+ switch admin {
+ case "ADMIN_STATE_DOWN":
return "Idle(Admin)"
+ case "ADMIN_STATE_PFX_CT":
+ return "Idle(PfxCt)"
}
if fsm == "BGP_FSM_IDLE" {
diff --git a/server/fsm.go b/server/fsm.go
index 48f4e095..01587668 100644
--- a/server/fsm.go
+++ b/server/fsm.go
@@ -109,6 +109,7 @@ type AdminState int
const (
ADMIN_STATE_UP AdminState = iota
ADMIN_STATE_DOWN
+ ADMIN_STATE_PFX_CT
)
func (s AdminState) String() string {
@@ -117,6 +118,8 @@ func (s AdminState) String() string {
return "ADMIN_STATE_UP"
case ADMIN_STATE_DOWN:
return "ADMIN_STATE_DOWN"
+ case ADMIN_STATE_PFX_CT:
+ return "ADMIN_STATE_PFX_CT"
default:
return "Unknown"
}
@@ -1086,15 +1089,14 @@ func (h *FSMHandler) sendMessageloop() error {
}
}
if m.Notification != nil {
+ if m.StayIdle {
+ // current user is only prefix-limit
+ // fix me if this is not the case
+ h.changeAdminState(ADMIN_STATE_PFX_CT)
+ }
if err := send(m.Notification); err != nil {
return nil
}
- if m.StayIdle {
- select {
- case h.fsm.adminStateCh <- ADMIN_STATE_DOWN:
- default:
- }
- }
}
case <-ticker.C:
if err := send(bgp.NewBGPKeepAliveMessage()); err != nil {
@@ -1272,7 +1274,7 @@ func (h *FSMHandler) changeAdminState(s AdminState) error {
"State": fsm.state,
}).Info("Administrative start")
- case ADMIN_STATE_DOWN:
+ case ADMIN_STATE_DOWN, ADMIN_STATE_PFX_CT:
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": fsm.pConf.Config.NeighborAddress,
diff --git a/server/peer.go b/server/peer.go
index 950526dd..cc71063a 100644
--- a/server/peer.go
+++ b/server/peer.go
@@ -33,15 +33,16 @@ const (
)
type Peer struct {
- tableId string
- gConf config.Global
- conf config.Neighbor
- fsm *FSM
- adjRibIn *table.AdjRib
- adjRibOut *table.AdjRib
- outgoing chan *FsmOutgoingMsg
- policy *table.RoutingPolicy
- localRib *table.TableManager
+ tableId string
+ gConf config.Global
+ conf config.Neighbor
+ fsm *FSM
+ adjRibIn *table.AdjRib
+ adjRibOut *table.AdjRib
+ outgoing chan *FsmOutgoingMsg
+ policy *table.RoutingPolicy
+ localRib *table.TableManager
+ prefixLimitWarned bool
}
func NewPeer(g config.Global, conf config.Neighbor, loc *table.TableManager, policy *table.RoutingPolicy) *Peer {
@@ -227,7 +228,7 @@ func (peer *Peer) handleRouteRefresh(e *FsmMsg) []*table.Path {
return accepted
}
-func (peer *Peer) handleUpdate(e *FsmMsg) ([]*table.Path, []bgp.RouteFamily) {
+func (peer *Peer) handleUpdate(e *FsmMsg) ([]*table.Path, []bgp.RouteFamily, *bgp.BGPMessage) {
m := e.MsgData.(*bgp.BGPMessage)
log.WithFields(log.Fields{
"Topic": "Peer",
@@ -237,6 +238,29 @@ func (peer *Peer) handleUpdate(e *FsmMsg) ([]*table.Path, []bgp.RouteFamily) {
peer.conf.Timers.State.UpdateRecvTime = time.Now().Unix()
if len(e.PathList) > 0 {
peer.adjRibIn.Update(e.PathList)
+ for _, family := range peer.fsm.pConf.AfiSafis {
+ k, _ := bgp.GetRouteFamily(string(family.AfiSafiName))
+ count := peer.adjRibIn.Count([]bgp.RouteFamily{k})
+ if maxPrefixes := int(family.PrefixLimit.Config.MaxPrefixes); maxPrefixes > 0 {
+ pct := int(family.PrefixLimit.Config.ShutdownThresholdPct)
+ if pct > 0 && !peer.prefixLimitWarned && count > (maxPrefixes*pct/100) {
+ peer.prefixLimitWarned = true
+ log.WithFields(log.Fields{
+ "Topic": "Peer",
+ "Key": peer.conf.Config.NeighborAddress,
+ "AddressFamily": family.AfiSafiName,
+ }).Warnf("prefix limit %d%% reached", pct)
+ }
+ if count > maxPrefixes {
+ log.WithFields(log.Fields{
+ "Topic": "Peer",
+ "Key": peer.conf.Config.NeighborAddress,
+ "AddressFamily": family.AfiSafiName,
+ }).Warnf("prefix limit reached")
+ return nil, nil, bgp.NewBGPNotificationMessage(bgp.BGP_ERROR_CEASE, bgp.BGP_ERROR_SUB_MAXIMUM_NUMBER_OF_PREFIXES_REACHED, nil)
+ }
+ }
+ }
paths := make([]*table.Path, 0, len(e.PathList))
eor := []bgp.RouteFamily{}
for _, path := range e.PathList {
@@ -254,9 +278,9 @@ func (peer *Peer) handleUpdate(e *FsmMsg) ([]*table.Path, []bgp.RouteFamily) {
paths = append(paths, path)
}
}
- return paths, eor
+ return paths, eor, nil
}
- return nil, nil
+ return nil, nil, nil
}
func (peer *Peer) startFSMHandler(incoming *channels.InfiniteChannel, stateCh chan *FsmMsg) {
diff --git a/server/server.go b/server/server.go
index af88f3ca..1b59402d 100644
--- a/server/server.go
+++ b/server/server.go
@@ -774,6 +774,7 @@ func (server *BgpServer) handleFSMMessage(peer *Peer, e *FsmMsg) []*SenderMsg {
} else {
drop = peer.configuredRFlist()
}
+ peer.prefixLimitWarned = false
peer.DropAll(drop)
msgs = server.dropPeerAllRoutes(peer, drop)
} else if peer.fsm.pConf.GracefulRestart.State.PeerRestarting && nextState == bgp.BGP_FSM_IDLE {
@@ -847,8 +848,10 @@ func (server *BgpServer) handleFSMMessage(peer *Peer, e *FsmMsg) []*SenderMsg {
case *bgp.MessageError:
return []*SenderMsg{newSenderMsg(peer, nil, bgp.NewBGPNotificationMessage(m.TypeCode, m.SubTypeCode, m.Data), false)}
case *bgp.BGPMessage:
- pathList, eor := peer.handleUpdate(e)
-
+ pathList, eor, notification := peer.handleUpdate(e)
+ if notification != nil {
+ return []*SenderMsg{newSenderMsg(peer, nil, notification, true)}
+ }
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]
l, _ := peer.fsm.LocalHostPort()
diff --git a/test/lib/base.py b/test/lib/base.py
index 29920451..d5dfc221 100644
--- a/test/lib/base.py
+++ b/test/lib/base.py
@@ -254,7 +254,7 @@ class BGPContainer(Container):
policies=None, passive=False,
is_rr_client=False, cluster_id=None,
flowspec=False, bridge='', reload_config=True, as2=False,
- graceful_restart=None, local_as=None):
+ graceful_restart=None, local_as=None, prefix_limit=None):
neigh_addr = ''
local_addr = ''
for me, you in itertools.product(self.ip_addrs, peer.ip_addrs):
@@ -283,7 +283,8 @@ class BGPContainer(Container):
'local_addr': local_addr,
'as2': as2,
'graceful_restart': graceful_restart,
- 'local_as': local_as}
+ 'local_as': local_as,
+ 'prefix_limit': prefix_limit}
if self.is_running and reload_config:
self.create_config()
self.reload_config()
diff --git a/test/lib/gobgp.py b/test/lib/gobgp.py
index b8413f40..36b4b86e 100644
--- a/test/lib/gobgp.py
+++ b/test/lib/gobgp.py
@@ -243,6 +243,10 @@ class GoBGPContainer(BGPContainer):
if info['local_as']:
n['config']['local-as'] = info['local_as']
+ if info['prefix_limit']:
+ for v in afi_safi_list:
+ v['prefix-limit'] = {'config': {'max-prefixes': info['prefix_limit'], 'shutdown-threshold-pct': 80 }}
+
if info['graceful_restart'] is not None:
n['graceful-restart'] = {'config': {'enabled': True, 'restart-time': 20}}
for afi_safi in afi_safi_list:
diff --git a/test/scenario_test/route_server_test.py b/test/scenario_test/route_server_test.py
index ab305e44..3c8f9356 100644
--- a/test/scenario_test/route_server_test.py
+++ b/test/scenario_test/route_server_test.py
@@ -59,7 +59,7 @@ class GoBGPTestBase(unittest.TestCase):
time.sleep(initial_wait_time)
for rs_client in rs_clients:
- g1.add_peer(rs_client, is_rs_client=True, passwd='passwd', passive=True)
+ g1.add_peer(rs_client, is_rs_client=True, passwd='passwd', passive=True, prefix_limit=10)
rs_client.add_peer(g1, passwd='passwd')
cls.gobgp = g1