diff options
-rw-r--r-- | config/util.go | 13 | ||||
-rw-r--r-- | packet/bgp/validate.go | 4 | ||||
-rw-r--r-- | packet/bgp/validate_test.go | 32 | ||||
-rw-r--r-- | server/fsm.go | 87 | ||||
-rw-r--r-- | server/server.go | 8 | ||||
-rw-r--r-- | server/server_test.go | 2 | ||||
-rw-r--r-- | table/adj.go | 3 | ||||
-rw-r--r-- | table/destination.go | 6 |
8 files changed, 107 insertions, 48 deletions
diff --git a/config/util.go b/config/util.go index 8ecf56d5..ab7ebfe3 100644 --- a/config/util.go +++ b/config/util.go @@ -69,11 +69,18 @@ func (c AfiSafis) ToRfList() ([]bgp.RouteFamily, error) { return rfs, nil } -func CreateRfMap(p *Neighbor) map[bgp.RouteFamily]bool { +func CreateRfMap(p *Neighbor) map[bgp.RouteFamily]bgp.BGPAddPathMode { rfs, _ := AfiSafis(p.AfiSafis).ToRfList() - rfMap := make(map[bgp.RouteFamily]bool) + mode := bgp.BGP_ADD_PATH_NONE + if p.AddPaths.Config.Receive { + mode |= bgp.BGP_ADD_PATH_RECEIVE + } + if p.AddPaths.Config.SendMax > 0 { + mode |= bgp.BGP_ADD_PATH_SEND + } + rfMap := make(map[bgp.RouteFamily]bgp.BGPAddPathMode) for _, rf := range rfs { - rfMap[rf] = true + rfMap[rf] = mode } return rfMap } diff --git a/packet/bgp/validate.go b/packet/bgp/validate.go index 13c66a77..77a125b9 100644 --- a/packet/bgp/validate.go +++ b/packet/bgp/validate.go @@ -8,7 +8,7 @@ import ( ) // Validator for BGPUpdate -func ValidateUpdateMsg(m *BGPUpdate, rfs map[RouteFamily]bool, doConfedCheck bool) (bool, error) { +func ValidateUpdateMsg(m *BGPUpdate, rfs map[RouteFamily]BGPAddPathMode, doConfedCheck bool) (bool, error) { eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) eSubCodeAttrList := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST) eSubCodeMissing := uint8(BGP_ERROR_SUB_MISSING_WELL_KNOWN_ATTRIBUTE) @@ -58,7 +58,7 @@ func ValidateUpdateMsg(m *BGPUpdate, rfs map[RouteFamily]bool, doConfedCheck boo return true, nil } -func ValidateAttribute(a PathAttributeInterface, rfs map[RouteFamily]bool, doConfedCheck bool) (bool, error) { +func ValidateAttribute(a PathAttributeInterface, rfs map[RouteFamily]BGPAddPathMode, doConfedCheck bool) (bool, error) { eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) eSubCodeBadOrigin := uint8(BGP_ERROR_SUB_INVALID_ORIGIN_ATTRIBUTE) diff --git a/packet/bgp/validate_test.go b/packet/bgp/validate_test.go index bcb74809..05b2fed7 100644 --- a/packet/bgp/validate_test.go +++ b/packet/bgp/validate_test.go @@ -41,29 +41,29 @@ func bgpupdateV6() *BGPMessage { func Test_Validate_CapV4(t *testing.T) { assert := assert.New(t) message := bgpupdate().Body.(*BGPUpdate) - res, err := ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv6_UC: true}, false) + res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv6_UC: BGP_ADD_PATH_BOTH}, false) assert.Equal(false, res) assert.Error(err) - res, err = ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, false) + res, err = ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false) assert.Equal(true, res) } func Test_Validate_CapV6(t *testing.T) { assert := assert.New(t) message := bgpupdateV6().Body.(*BGPUpdate) - res, err := ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv6_UC: true}, false) + res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv6_UC: BGP_ADD_PATH_BOTH}, false) assert.Equal(true, res) assert.NoError(err) - res, err = ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, false) + res, err = ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false) assert.Equal(false, res) } func Test_Validate_OK(t *testing.T) { assert := assert.New(t) message := bgpupdate().Body.(*BGPUpdate) - res, err := ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, false) + res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false) assert.Equal(true, res) assert.NoError(err) @@ -151,7 +151,7 @@ func Test_Validate_duplicate_attribute(t *testing.T) { origin.DecodeFromBytes(originBytes) message.PathAttributes = append(message.PathAttributes, origin) - res, err := ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, false) + res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false) assert.Equal(false, res) assert.Error(err) e := err.(*MessageError) @@ -164,7 +164,7 @@ func Test_Validate_mandatory_missing(t *testing.T) { assert := assert.New(t) message := bgpupdate().Body.(*BGPUpdate) message.PathAttributes = message.PathAttributes[1:] - res, err := ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, false) + res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false) assert.Equal(false, res) assert.Error(err) e := err.(*MessageError) @@ -180,7 +180,7 @@ func Test_Validate_mandatory_missing_nocheck(t *testing.T) { message.PathAttributes = message.PathAttributes[1:] message.NLRI = nil - res, err := ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, false) + res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false) assert.Equal(true, res) assert.NoError(err) } @@ -194,7 +194,7 @@ func Test_Validate_invalid_origin(t *testing.T) { origin.DecodeFromBytes(originBytes) message.PathAttributes[0] = origin - res, err := ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, false) + res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false) assert.Equal(false, res) assert.Error(err) e := err.(*MessageError) @@ -215,7 +215,7 @@ func Test_Validate_invalid_nexthop_zero(t *testing.T) { nexthop.DecodeFromBytes(nexthopBytes) message.PathAttributes[2] = nexthop - res, err := ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, false) + res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false) assert.Equal(false, res) assert.Error(err) e := err.(*MessageError) @@ -236,7 +236,7 @@ func Test_Validate_invalid_nexthop_lo(t *testing.T) { nexthop.DecodeFromBytes(nexthopBytes) message.PathAttributes[2] = nexthop - res, err := ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, false) + res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false) assert.Equal(false, res) assert.Error(err) e := err.(*MessageError) @@ -257,7 +257,7 @@ func Test_Validate_invalid_nexthop_de(t *testing.T) { nexthop.DecodeFromBytes(nexthopBytes) message.PathAttributes[2] = nexthop - res, err := ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, false) + res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false) assert.Equal(false, res) assert.Error(err) e := err.(*MessageError) @@ -277,7 +277,7 @@ func Test_Validate_unrecognized_well_known(t *testing.T) { unknown.DecodeFromBytes(unknownBytes) message.PathAttributes = append(message.PathAttributes, unknown) - res, err := ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, false) + res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false) assert.Equal(false, res) assert.Error(err) e := err.(*MessageError) @@ -292,7 +292,7 @@ func Test_Validate_aspath(t *testing.T) { message := bgpupdate().Body.(*BGPUpdate) // VALID AS_PATH - res, err := ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, true) + res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, true) assert.Equal(true, res) // CONFED_SET @@ -310,7 +310,7 @@ func Test_Validate_aspath(t *testing.T) { } message.PathAttributes = newAttrs - res, err = ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, true) + res, err = ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, true) assert.Equal(false, res) assert.Error(err) e := err.(*MessageError) @@ -333,7 +333,7 @@ func Test_Validate_aspath(t *testing.T) { } message.PathAttributes = newAttrs - res, err = ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, true) + res, err = ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, true) assert.Equal(false, res) assert.Error(err) e = err.(*MessageError) diff --git a/server/fsm.go b/server/fsm.go index afd04b3e..953e2f7d 100644 --- a/server/fsm.go +++ b/server/fsm.go @@ -124,7 +124,7 @@ type FSM struct { adminStateCh chan AdminStateOperation getActiveCh chan struct{} h *FSMHandler - rfMap map[bgp.RouteFamily]bool + rfMap map[bgp.RouteFamily]bgp.BGPAddPathMode capMap map[bgp.BGPCapabilityCode][]bgp.ParameterCapabilityInterface recvOpen *bgp.BGPMessage peerInfo *table.PeerInfo @@ -132,6 +132,7 @@ type FSM struct { gracefulRestartTimer *time.Timer twoByteAsTrans bool version uint + marshallingOptions *bgp.MarshallingOption } func (fsm *FSM) bgpMessageStateUpdate(MessageType uint8, isIn bool) { @@ -212,7 +213,7 @@ func NewFSM(gConf *config.Global, pConf *config.Neighbor, policy *table.RoutingP adminState: adminState, adminStateCh: make(chan AdminStateOperation, 1), getActiveCh: make(chan struct{}), - rfMap: make(map[bgp.RouteFamily]bool), + rfMap: make(map[bgp.RouteFamily]bgp.BGPAddPathMode), capMap: make(map[bgp.BGPCapabilityCode][]bgp.ParameterCapabilityInterface), peerInfo: table.NewPeerInfo(gConf, pConf), policy: policy, @@ -614,6 +615,23 @@ func capabilitiesFromConfig(pConf *config.Neighbor) []bgp.ParameterCapabilityInt cap := bgp.NewCapExtendedNexthop(tuples) caps = append(caps, cap) } + + var mode bgp.BGPAddPathMode + if pConf.AddPaths.Config.Receive { + mode |= bgp.BGP_ADD_PATH_RECEIVE + } + if pConf.AddPaths.Config.SendMax > 0 { + mode |= bgp.BGP_ADD_PATH_SEND + } + if uint8(mode) > 0 { + items := make([]*bgp.CapAddPathTuple, 0, len(pConf.AfiSafis)) + for _, rf := range pConf.AfiSafis { + k, _ := bgp.GetRouteFamily(string(rf.Config.AfiSafiName)) + items = append(items, bgp.NewCapAddPathTuple(k, mode)) + } + caps = append(caps, bgp.NewCapAddPath(items)) + } + return caps } @@ -703,7 +721,7 @@ func (h *FSMHandler) recvMessageWithError() (*FsmMsg, error) { } now := time.Now() - m, err := bgp.ParseBGPBody(hd, bodyBuf) + m, err := bgp.ParseBGPBody(hd, bodyBuf, h.fsm.marshallingOptions) if err == nil { h.fsm.bgpMessageStateUpdate(m.Header.Type, true) err = bgp.ValidateBGPMessage(m) @@ -841,10 +859,8 @@ func (h *FSMHandler) recvMessage() error { return nil } -func open2Cap(open *bgp.BGPOpen, n *config.Neighbor) (map[bgp.BGPCapabilityCode][]bgp.ParameterCapabilityInterface, map[bgp.RouteFamily]bool) { +func open2Cap(open *bgp.BGPOpen, n *config.Neighbor) (map[bgp.BGPCapabilityCode][]bgp.ParameterCapabilityInterface, map[bgp.RouteFamily]bgp.BGPAddPathMode) { capMap := make(map[bgp.BGPCapabilityCode][]bgp.ParameterCapabilityInterface) - rfMap := config.CreateRfMap(n) - r := make(map[bgp.RouteFamily]bool) for _, p := range open.OptParams { if paramCap, y := p.(*bgp.OptionParameterCapability); y { for _, c := range paramCap.Capability { @@ -853,26 +869,53 @@ func open2Cap(open *bgp.BGPOpen, n *config.Neighbor) (map[bgp.BGPCapabilityCode] m = make([]bgp.ParameterCapabilityInterface, 0, 1) } capMap[c.Code()] = append(m, c) + } + } + } - if c.Code() == bgp.BGP_CAP_MULTIPROTOCOL { - m := c.(*bgp.CapMultiProtocol) - r[m.CapValue] = true - } + // squash add path cap + if caps, y := capMap[bgp.BGP_CAP_ADD_PATH]; y { + items := make([]*bgp.CapAddPathTuple, 0, len(caps)) + for _, c := range caps { + for _, i := range c.(*bgp.CapAddPath).Tuples { + items = append(items, i) } } + capMap[bgp.BGP_CAP_ADD_PATH] = []bgp.ParameterCapabilityInterface{bgp.NewCapAddPath(items)} } - if len(r) > 0 { - for rf, _ := range rfMap { - if _, y := r[rf]; !y { - delete(rfMap, rf) + // remote open message may not include multi-protocol capability + if _, y := capMap[bgp.BGP_CAP_MULTIPROTOCOL]; !y { + capMap[bgp.BGP_CAP_MULTIPROTOCOL] = []bgp.ParameterCapabilityInterface{bgp.NewCapMultiProtocol(bgp.RF_IPv4_UC)} + } + + local := config.CreateRfMap(n) + remote := make(map[bgp.RouteFamily]bgp.BGPAddPathMode) + for _, c := range capMap[bgp.BGP_CAP_MULTIPROTOCOL] { + family := c.(*bgp.CapMultiProtocol).CapValue + remote[family] = bgp.BGP_ADD_PATH_NONE + for _, a := range capMap[bgp.BGP_CAP_ADD_PATH] { + for _, i := range a.(*bgp.CapAddPath).Tuples { + if i.RouteFamily == family { + remote[family] = i.Mode + } } } - } else { - rfMap = make(map[bgp.RouteFamily]bool) - rfMap[bgp.RF_IPv4_UC] = true } - return capMap, rfMap + negotiated := make(map[bgp.RouteFamily]bgp.BGPAddPathMode) + for family, mode := range local { + if m, y := remote[family]; y { + n := bgp.BGP_ADD_PATH_NONE + if mode&bgp.BGP_ADD_PATH_SEND > 0 && m&bgp.BGP_ADD_PATH_RECEIVE > 0 { + n |= bgp.BGP_ADD_PATH_SEND + } + if mode&bgp.BGP_ADD_PATH_RECEIVE > 0 && m&bgp.BGP_ADD_PATH_SEND > 0 { + n |= bgp.BGP_ADD_PATH_RECEIVE + } + negotiated[family] = n + } + } + return capMap, negotiated } func (h *FSMHandler) opensent() (bgp.FSMState, FsmStateReason) { @@ -955,6 +998,12 @@ func (h *FSMHandler) opensent() (bgp.FSMState, FsmStateReason) { fsm.peerInfo.ID = body.ID fsm.capMap, fsm.rfMap = open2Cap(body, fsm.pConf) + if _, y := fsm.capMap[bgp.BGP_CAP_ADD_PATH]; y { + fsm.marshallingOptions = &bgp.MarshallingOption{ + AddPath: fsm.rfMap, + } + } + // calculate HoldTime // RFC 4271 P.13 // a BGP speaker MUST calculate the value of the Hold Timer @@ -1202,7 +1251,7 @@ func (h *FSMHandler) sendMessageloop() error { table.UpdatePathAttrs2ByteAs(m.Body.(*bgp.BGPUpdate)) table.UpdatePathAggregator2ByteAs(m.Body.(*bgp.BGPUpdate)) } - b, err := m.Serialize() + b, err := m.Serialize(h.fsm.marshallingOptions) if err != nil { log.WithFields(log.Fields{ "Topic": "Peer", diff --git a/server/server.go b/server/server.go index b821ea82..bbbfb524 100644 --- a/server/server.go +++ b/server/server.go @@ -346,7 +346,7 @@ func filterpath(peer *Peer, path, old *table.Path) *table.Path { if peer.isIBGPPeer() { ignore := false //RFC4684 Constrained Route Distribution - if peer.fsm.rfMap[bgp.RF_RTC_UC] && path.GetRouteFamily() != bgp.RF_RTC_UC { + if _, y := peer.fsm.rfMap[bgp.RF_RTC_UC]; y && path.GetRouteFamily() != bgp.RF_RTC_UC { ignore = true for _, ext := range path.GetExtCommunities() { for _, path := range peer.adjRibIn.PathList([]bgp.RouteFamily{bgp.RF_RTC_UC}, true) { @@ -870,7 +870,8 @@ func (server *BgpServer) handleFSMMessage(peer *Peer, e *FsmMsg) { // waiting sending non-route-target NLRIs since the peer won't send // any routes (and EORs) before we send ours (or deferral-timer expires). var pathList []*table.Path - if c := config.GetAfiSafi(peer.fsm.pConf, bgp.RF_RTC_UC); !peer.fsm.pConf.GracefulRestart.State.PeerRestarting && peer.fsm.rfMap[bgp.RF_RTC_UC] && c.RouteTargetMembership.Config.DeferralTime > 0 { + _, y := peer.fsm.rfMap[bgp.RF_RTC_UC] + if c := config.GetAfiSafi(peer.fsm.pConf, bgp.RF_RTC_UC); y && !peer.fsm.pConf.GracefulRestart.State.PeerRestarting && c.RouteTargetMembership.Config.DeferralTime > 0 { pathList, _ = peer.getBestFromLocal([]bgp.RouteFamily{bgp.RF_RTC_UC}) t := c.RouteTargetMembership.Config.DeferralTime for _, f := range peer.configuredRFlist() { @@ -1456,6 +1457,7 @@ func (s *BgpServer) softResetOut(addr string, family bgp.RouteFamily, deferral b } if deferral { + _, y := peer.fsm.rfMap[bgp.RF_RTC_UC] if peer.fsm.pConf.GracefulRestart.State.LocalRestarting { peer.fsm.pConf.GracefulRestart.State.LocalRestarting = false log.WithFields(log.Fields{ @@ -1463,7 +1465,7 @@ func (s *BgpServer) softResetOut(addr string, family bgp.RouteFamily, deferral b "Key": peer.ID(), "Families": families, }).Debug("deferral timer expired") - } else if c := config.GetAfiSafi(peer.fsm.pConf, bgp.RF_RTC_UC); peer.fsm.rfMap[bgp.RF_RTC_UC] && !c.MpGracefulRestart.State.EndOfRibReceived { + } else if c := config.GetAfiSafi(peer.fsm.pConf, bgp.RF_RTC_UC); y && !c.MpGracefulRestart.State.EndOfRibReceived { log.WithFields(log.Fields{ "Topic": "Peer", "Key": peer.ID(), diff --git a/server/server_test.go b/server/server_test.go index fb7b97f3..b8dc58f5 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -209,7 +209,7 @@ func newPeerandInfo(myAs, as uint32, address string, rib *table.TableManager) (* rib, policy) for _, f := range rib.GetRFlist() { - p.fsm.rfMap[f] = true + p.fsm.rfMap[f] = bgp.BGP_ADD_PATH_NONE } return p, &table.PeerInfo{AS: as, Address: net.ParseIP(address)} } diff --git a/table/adj.go b/table/adj.go index 5ef540f6..05a795be 100644 --- a/table/adj.go +++ b/table/adj.go @@ -17,6 +17,7 @@ package table import ( "fmt" + "github.com/osrg/gobgp/packet/bgp" ) @@ -44,7 +45,7 @@ func (adj *AdjRib) Update(pathList []*Path) { continue } rf := path.GetRouteFamily() - key := path.getPrefix() + key := fmt.Sprintf("%d:%s", path.GetNlri().PathIdentifier(), path.getPrefix()) old, found := adj.table[rf][key] if path.IsWithdraw { diff --git a/table/destination.go b/table/destination.go index 6f4f95ad..cef2086f 100644 --- a/table/destination.go +++ b/table/destination.go @@ -378,8 +378,8 @@ func (dest *Destination) explicitWithdraw() paths { for _, withdraw := range dest.withdrawList { isFound := false for _, path := range dest.knownPathList { - // We have a match if the source are same. - if path.GetSource().Equal(withdraw.GetSource()) { + // We have a match if the source and path-id are same. + if path.GetSource().Equal(withdraw.GetSource()) && path.GetNlri().PathIdentifier() == withdraw.GetNlri().PathIdentifier() { isFound = true // this path is referenced in peer's adj-rib-in // when there was no policy modification applied. @@ -430,7 +430,7 @@ func (dest *Destination) implicitWithdraw() paths { // version num. as newPaths are implicit withdrawal of old // paths and when doing RouteRefresh (not EnhancedRouteRefresh) // we get same paths again. - if newPath.GetSource().Equal(path.GetSource()) { + if newPath.GetSource().Equal(path.GetSource()) && newPath.GetNlri().PathIdentifier() == path.GetNlri().PathIdentifier() { log.WithFields(log.Fields{ "Topic": "Table", "Key": dest.GetNlri().String(), |