summaryrefslogtreecommitdiffhomepage
path: root/server/fsm.go
diff options
context:
space:
mode:
Diffstat (limited to 'server/fsm.go')
-rw-r--r--server/fsm.go75
1 files changed, 55 insertions, 20 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