summaryrefslogtreecommitdiffhomepage
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/fsm.go75
-rw-r--r--server/fsm_test.go9
-rw-r--r--server/server.go35
3 files changed, 91 insertions, 28 deletions
diff --git a/server/fsm.go b/server/fsm.go
index f623f399..e1b85cd0 100644
--- a/server/fsm.go
+++ b/server/fsm.go
@@ -600,6 +600,30 @@ func readAll(conn net.Conn, length int) ([]byte, error) {
return buf, nil
}
+func getPathAttrFromBGPUpdate(m *bgp.BGPUpdate, typ bgp.BGPAttrType) bgp.PathAttributeInterface {
+ for _, a := range m.PathAttributes {
+ if a.GetType() == typ {
+ return a
+ }
+ }
+ return nil
+}
+
+func hasOwnASLoop(ownAS uint32, limit int, aspath *bgp.PathAttributeAsPath) bool {
+ cnt := 0
+ for _, i := range aspath.Value {
+ for _, as := range i.(*bgp.As4PathParam).AS {
+ if as == ownAS {
+ cnt++
+ if cnt > limit {
+ return true
+ }
+ }
+ }
+ }
+ return false
+}
+
func (h *FSMHandler) recvMessageWithError() (*FsmMsg, error) {
sendToErrorCh := func(reason FsmStateReason) {
// probably doesn't happen but be cautious
@@ -671,6 +695,11 @@ func (h *FSMHandler) recvMessageWithError() (*FsmMsg, error) {
case bgp.BGP_MSG_UPDATE:
body := m.Body.(*bgp.BGPUpdate)
confedCheck := !config.IsConfederationMember(h.fsm.gConf, h.fsm.pConf) && config.IsEBGPPeer(h.fsm.gConf, h.fsm.pConf)
+
+ fmsg.payload = make([]byte, len(headerBuf)+len(bodyBuf))
+ copy(fmsg.payload, headerBuf)
+ copy(fmsg.payload[len(headerBuf):], bodyBuf)
+
_, err = bgp.ValidateUpdateMsg(body, h.fsm.rfMap, confedCheck)
if err != nil {
log.WithFields(log.Fields{
@@ -680,28 +709,34 @@ func (h *FSMHandler) recvMessageWithError() (*FsmMsg, error) {
"error": err,
}).Warn("malformed BGP update message")
fmsg.MsgData = err
- } else {
- // FIXME: we should use the original message for bmp/mrt
- table.UpdatePathAttrs4ByteAs(body)
- err = table.UpdatePathAggregator4ByteAs(body)
- if err == nil {
- fmsg.PathList = table.ProcessMessage(m, h.fsm.peerInfo, fmsg.timestamp)
- id := h.fsm.pConf.Config.NeighborAddress
- for _, path := range fmsg.PathList {
- if path.IsEOR() {
- continue
- }
- if h.fsm.policy.ApplyPolicy(id, table.POLICY_DIRECTION_IN, path, nil) == nil {
- path.Filter(id, table.POLICY_DIRECTION_IN)
- }
- }
- } else {
- fmsg.MsgData = err
+ return fmsg, err
+ }
+
+ table.UpdatePathAttrs4ByteAs(body)
+ if err = table.UpdatePathAggregator4ByteAs(body); err != nil {
+ fmsg.MsgData = err
+ return fmsg, err
+ }
+
+ // RFC4271 9.1.2 Phase 2: Route Selection
+ //
+ // If the AS_PATH attribute of a BGP route contains an AS loop, the BGP
+ // route should be excluded from the Phase 2 decision function.
+ var asLoop bool
+ if attr := getPathAttrFromBGPUpdate(body, bgp.BGP_ATTR_TYPE_AS_PATH); attr != nil {
+ asLoop = hasOwnASLoop(h.fsm.peerInfo.LocalAS, int(h.fsm.pConf.AsPathOptions.Config.AllowOwnAs), attr.(*bgp.PathAttributeAsPath))
+ }
+
+ fmsg.PathList = table.ProcessMessage(m, h.fsm.peerInfo, fmsg.timestamp)
+ id := h.fsm.pConf.Config.NeighborAddress
+ for _, path := range fmsg.PathList {
+ if path.IsEOR() {
+ continue
+ }
+ if asLoop || (h.fsm.policy.ApplyPolicy(id, table.POLICY_DIRECTION_IN, path, nil) == nil) {
+ path.Filter(id, table.POLICY_DIRECTION_IN)
}
}
- fmsg.payload = make([]byte, len(headerBuf)+len(bodyBuf))
- copy(fmsg.payload, headerBuf)
- copy(fmsg.payload[len(headerBuf):], bodyBuf)
fallthrough
case bgp.BGP_MSG_KEEPALIVE:
// if the length of h.holdTimerResetCh
diff --git a/server/fsm_test.go b/server/fsm_test.go
index 0fb67f98..aea6700b 100644
--- a/server/fsm_test.go
+++ b/server/fsm_test.go
@@ -287,6 +287,15 @@ func TestFSMHandlerEstablished_HoldtimeZero(t *testing.T) {
assert.Equal(0, len(m.sendBuf))
}
+func TestCheckOwnASLoop(t *testing.T) {
+ assert := assert.New(t)
+ aspathParam := []bgp.AsPathParamInterface{bgp.NewAs4PathParam(2, []uint32{65100})}
+ aspath := bgp.NewPathAttributeAsPath(aspathParam)
+ assert.False(hasOwnASLoop(65100, 10, aspath))
+ assert.True(hasOwnASLoop(65100, 0, aspath))
+ assert.False(hasOwnASLoop(65200, 0, aspath))
+}
+
func makePeerAndHandler() (*Peer, *FSMHandler) {
p := &Peer{
fsm: NewFSM(&config.Global{}, &config.Neighbor{}, table.NewRoutingPolicy()),
diff --git a/server/server.go b/server/server.go
index f3861de3..6e20979b 100644
--- a/server/server.go
+++ b/server/server.go
@@ -1317,7 +1317,17 @@ func (s *BgpServer) softResetIn(addr string, family bgp.RouteFamily) error {
for _, path := range peer.adjRibIn.PathList(families, false) {
exResult := path.Filtered(peer.ID())
path.Filter(peer.ID(), table.POLICY_DIRECTION_NONE)
- if s.policy.ApplyPolicy(peer.ID(), table.POLICY_DIRECTION_IN, path, nil) != nil {
+
+ // RFC4271 9.1.2 Phase 2: Route Selection
+ //
+ // If the AS_PATH attribute of a BGP route contains an AS loop, the BGP
+ // route should be excluded from the Phase 2 decision function.
+ var asLoop bool
+ if aspath := path.GetAsPath(); aspath != nil {
+ asLoop = hasOwnASLoop(peer.fsm.peerInfo.LocalAS, int(peer.fsm.pConf.AsPathOptions.Config.AllowOwnAs), aspath)
+ }
+
+ if !asLoop && s.policy.ApplyPolicy(peer.ID(), table.POLICY_DIRECTION_IN, path, nil) != nil {
pathList = append(pathList, path.Clone(false))
// this path still in rib's
// knownPathList. We can't
@@ -1482,13 +1492,13 @@ func (s *BgpServer) GetAdjRib(addr string, family bgp.RouteFamily, in bool, pref
if !ok {
return fmt.Errorf("Neighbor that has %v doesn't exist.", addr)
}
- id := peer.TableID()
+ id := peer.ID()
var adjRib *table.AdjRib
if in {
adjRib = peer.adjRibIn
} else {
- adjRib = table.NewAdjRib(peer.ID(), peer.configuredRFlist())
+ adjRib = table.NewAdjRib(id, peer.configuredRFlist())
accepted, _ := peer.getBestFromLocal(peer.configuredRFlist())
adjRib.Update(accepted)
}
@@ -1707,7 +1717,7 @@ func (s *BgpServer) DeleteNeighbor(c *config.Neighbor) error {
}, true)
}
-func (s *BgpServer) UpdateNeighbor(c *config.Neighbor) (policyUpdated bool, err error) {
+func (s *BgpServer) UpdateNeighbor(c *config.Neighbor) (needsSoftResetIn bool, err error) {
err = s.mgmtOperation(func() error {
addr := c.Config.NeighborAddress
peer, ok := s.neighborMap[addr]
@@ -1722,10 +1732,19 @@ func (s *BgpServer) UpdateNeighbor(c *config.Neighbor) (policyUpdated bool, err
}).Info("Update ApplyPolicy")
s.policy.Reset(nil, map[string]config.ApplyPolicy{peer.ID(): c.ApplyPolicy})
peer.fsm.pConf.ApplyPolicy = c.ApplyPolicy
- policyUpdated = true
+ needsSoftResetIn = true
}
original := peer.fsm.pConf
+ if !original.AsPathOptions.Config.Equal(&c.AsPathOptions.Config) {
+ log.WithFields(log.Fields{
+ "Topic": "Peer",
+ "Key": peer.ID(),
+ }).Info("Update aspath options")
+ peer.fsm.pConf.AsPathOptions = c.AsPathOptions
+ needsSoftResetIn = true
+ }
+
if !original.Config.Equal(&c.Config) || !original.Transport.Config.Equal(&c.Transport.Config) || config.CheckAfiSafisChange(original.AfiSafis, c.AfiSafis) {
sub := uint8(bgp.BGP_ERROR_SUB_OTHER_CONFIGURATION_CHANGE)
if original.Config.AdminDown != c.Config.AdminDown {
@@ -1738,7 +1757,7 @@ func (s *BgpServer) UpdateNeighbor(c *config.Neighbor) (policyUpdated bool, err
"Topic": "Peer",
"Key": peer.ID(),
"State": state,
- }).Info("update admin-state configuration")
+ }).Info("Update admin-state configuration")
} else if original.Config.PeerAs != c.Config.PeerAs {
sub = bgp.BGP_ERROR_SUB_PEER_DECONFIGURED
}
@@ -1763,7 +1782,7 @@ func (s *BgpServer) UpdateNeighbor(c *config.Neighbor) (policyUpdated bool, err
log.WithFields(log.Fields{
"Topic": "Peer",
"Key": peer.ID(),
- }).Info("update timer configuration")
+ }).Info("Update timer configuration")
peer.fsm.pConf.Timers.Config = c.Timers.Config
}
@@ -1778,7 +1797,7 @@ func (s *BgpServer) UpdateNeighbor(c *config.Neighbor) (policyUpdated bool, err
}
return err
}, true)
- return policyUpdated, err
+ return needsSoftResetIn, err
}
func (s *BgpServer) addrToPeers(addr string) (l []*Peer, err error) {