diff options
Diffstat (limited to 'server/peer.go')
-rw-r--r-- | server/peer.go | 522 |
1 files changed, 0 insertions, 522 deletions
diff --git a/server/peer.go b/server/peer.go deleted file mode 100644 index 3a43fac9..00000000 --- a/server/peer.go +++ /dev/null @@ -1,522 +0,0 @@ -// Copyright (C) 2014-2016 Nippon Telegraph and Telephone Corporation. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package server - -import ( - "fmt" - "net" - "time" - - "github.com/eapache/channels" - log "github.com/sirupsen/logrus" - - "github.com/osrg/gobgp/config" - "github.com/osrg/gobgp/packet/bgp" - "github.com/osrg/gobgp/table" -) - -const ( - FLOP_THRESHOLD = time.Second * 30 - MIN_CONNECT_RETRY = 10 -) - -type PeerGroup struct { - Conf *config.PeerGroup - members map[string]config.Neighbor - dynamicNeighbors map[string]*config.DynamicNeighbor -} - -func NewPeerGroup(c *config.PeerGroup) *PeerGroup { - return &PeerGroup{ - Conf: c, - members: make(map[string]config.Neighbor), - dynamicNeighbors: make(map[string]*config.DynamicNeighbor), - } -} - -func (pg *PeerGroup) AddMember(c config.Neighbor) { - pg.members[c.State.NeighborAddress] = c -} - -func (pg *PeerGroup) DeleteMember(c config.Neighbor) { - delete(pg.members, c.State.NeighborAddress) -} - -func (pg *PeerGroup) AddDynamicNeighbor(c *config.DynamicNeighbor) { - pg.dynamicNeighbors[c.Config.Prefix] = c -} - -func newDynamicPeer(g *config.Global, neighborAddress string, pg *config.PeerGroup, loc *table.TableManager, policy *table.RoutingPolicy) *Peer { - conf := config.Neighbor{ - Config: config.NeighborConfig{ - PeerGroup: pg.Config.PeerGroupName, - }, - State: config.NeighborState{ - NeighborAddress: neighborAddress, - }, - Transport: config.Transport{ - Config: config.TransportConfig{ - PassiveMode: true, - }, - }, - } - if err := config.OverwriteNeighborConfigWithPeerGroup(&conf, pg); err != nil { - log.WithFields(log.Fields{ - "Topic": "Peer", - "Key": neighborAddress, - }).Debugf("Can't overwrite neighbor config: %s", err) - return nil - } - if err := config.SetDefaultNeighborConfigValues(&conf, pg, g); err != nil { - log.WithFields(log.Fields{ - "Topic": "Peer", - "Key": neighborAddress, - }).Debugf("Can't set default config: %s", err) - return nil - } - peer := NewPeer(g, &conf, loc, policy) - peer.fsm.state = bgp.BGP_FSM_ACTIVE - return peer -} - -type Peer struct { - tableId string - fsm *FSM - adjRibIn *table.AdjRib - outgoing *channels.InfiniteChannel - policy *table.RoutingPolicy - localRib *table.TableManager - prefixLimitWarned map[bgp.RouteFamily]bool - llgrEndChs []chan struct{} -} - -func NewPeer(g *config.Global, conf *config.Neighbor, loc *table.TableManager, policy *table.RoutingPolicy) *Peer { - peer := &Peer{ - outgoing: channels.NewInfiniteChannel(), - localRib: loc, - policy: policy, - fsm: NewFSM(g, conf, policy), - prefixLimitWarned: make(map[bgp.RouteFamily]bool), - } - if peer.isRouteServerClient() { - peer.tableId = conf.State.NeighborAddress - } else { - peer.tableId = table.GLOBAL_RIB_NAME - } - rfs, _ := config.AfiSafis(conf.AfiSafis).ToRfList() - peer.adjRibIn = table.NewAdjRib(rfs) - return peer -} - -func (peer *Peer) AS() uint32 { - return peer.fsm.pConf.State.PeerAs -} - -func (peer *Peer) ID() string { - return peer.fsm.pConf.State.NeighborAddress -} - -func (peer *Peer) TableID() string { - return peer.tableId -} - -func (peer *Peer) isIBGPPeer() bool { - return peer.fsm.pConf.State.PeerAs == peer.fsm.gConf.Config.As -} - -func (peer *Peer) isRouteServerClient() bool { - return peer.fsm.pConf.RouteServer.Config.RouteServerClient -} - -func (peer *Peer) isRouteReflectorClient() bool { - return peer.fsm.pConf.RouteReflector.Config.RouteReflectorClient -} - -func (peer *Peer) isGracefulRestartEnabled() bool { - return peer.fsm.pConf.GracefulRestart.State.Enabled -} - -func (peer *Peer) getAddPathMode(family bgp.RouteFamily) bgp.BGPAddPathMode { - if mode, y := peer.fsm.rfMap[family]; y { - return mode - } - return bgp.BGP_ADD_PATH_NONE -} - -func (peer *Peer) isAddPathReceiveEnabled(family bgp.RouteFamily) bool { - return (peer.getAddPathMode(family) & bgp.BGP_ADD_PATH_RECEIVE) > 0 -} - -func (peer *Peer) isAddPathSendEnabled(family bgp.RouteFamily) bool { - return (peer.getAddPathMode(family) & bgp.BGP_ADD_PATH_SEND) > 0 -} - -func (peer *Peer) isDynamicNeighbor() bool { - return peer.fsm.pConf.Config.NeighborAddress == "" && peer.fsm.pConf.Config.NeighborInterface == "" -} - -func (peer *Peer) recvedAllEOR() bool { - for _, a := range peer.fsm.pConf.AfiSafis { - if s := a.MpGracefulRestart.State; s.Enabled && !s.EndOfRibReceived { - return false - } - } - return true -} - -func (peer *Peer) configuredRFlist() []bgp.RouteFamily { - rfs, _ := config.AfiSafis(peer.fsm.pConf.AfiSafis).ToRfList() - return rfs -} - -func (peer *Peer) negotiatedRFList() []bgp.RouteFamily { - l := make([]bgp.RouteFamily, 0, len(peer.fsm.rfMap)) - for family, _ := range peer.fsm.rfMap { - l = append(l, family) - } - return l -} - -func (peer *Peer) toGlobalFamilies(families []bgp.RouteFamily) []bgp.RouteFamily { - if peer.fsm.pConf.Config.Vrf != "" { - fs := make([]bgp.RouteFamily, 0, len(families)) - for _, f := range families { - switch f { - case bgp.RF_IPv4_UC: - fs = append(fs, bgp.RF_IPv4_VPN) - case bgp.RF_IPv6_UC: - fs = append(fs, bgp.RF_IPv6_VPN) - default: - log.WithFields(log.Fields{ - "Topic": "Peer", - "Key": peer.ID(), - "Family": f, - "VRF": peer.fsm.pConf.Config.Vrf, - }).Warn("invalid family configured for neighbor with vrf") - } - } - families = fs - } - return families -} - -func classifyFamilies(all, part []bgp.RouteFamily) ([]bgp.RouteFamily, []bgp.RouteFamily) { - a := []bgp.RouteFamily{} - b := []bgp.RouteFamily{} - for _, f := range all { - p := true - for _, g := range part { - if f == g { - p = false - a = append(a, f) - break - } - } - if p { - b = append(b, f) - } - } - return a, b -} - -func (peer *Peer) forwardingPreservedFamilies() ([]bgp.RouteFamily, []bgp.RouteFamily) { - list := []bgp.RouteFamily{} - for _, a := range peer.fsm.pConf.AfiSafis { - if s := a.MpGracefulRestart.State; s.Enabled && s.Received { - list = append(list, a.State.Family) - } - } - return classifyFamilies(peer.configuredRFlist(), list) -} - -func (peer *Peer) llgrFamilies() ([]bgp.RouteFamily, []bgp.RouteFamily) { - list := []bgp.RouteFamily{} - for _, a := range peer.fsm.pConf.AfiSafis { - if a.LongLivedGracefulRestart.State.Enabled { - list = append(list, a.State.Family) - } - } - return classifyFamilies(peer.configuredRFlist(), list) -} - -func (peer *Peer) isLLGREnabledFamily(family bgp.RouteFamily) bool { - if !peer.fsm.pConf.GracefulRestart.Config.LongLivedEnabled { - return false - } - fs, _ := peer.llgrFamilies() - for _, f := range fs { - if f == family { - return true - } - } - return false -} - -func (peer *Peer) llgrRestartTime(family bgp.RouteFamily) uint32 { - for _, a := range peer.fsm.pConf.AfiSafis { - if a.State.Family == family { - return a.LongLivedGracefulRestart.State.PeerRestartTime - } - } - return 0 -} - -func (peer *Peer) llgrRestartTimerExpired(family bgp.RouteFamily) bool { - all := true - for _, a := range peer.fsm.pConf.AfiSafis { - if a.State.Family == family { - a.LongLivedGracefulRestart.State.PeerRestartTimerExpired = true - } - s := a.LongLivedGracefulRestart.State - if s.Received && !s.PeerRestartTimerExpired { - all = false - } - } - return all -} - -func (peer *Peer) markLLGRStale(fs []bgp.RouteFamily) []*table.Path { - paths := peer.adjRibIn.PathList(fs, true) - for i, p := range paths { - doStale := true - for _, c := range p.GetCommunities() { - if c == uint32(bgp.COMMUNITY_NO_LLGR) { - doStale = false - p = p.Clone(true) - break - } - } - if doStale { - p = p.Clone(false) - p.SetCommunities([]uint32{uint32(bgp.COMMUNITY_LLGR_STALE)}, false) - } - paths[i] = p - } - return paths -} - -func (peer *Peer) stopPeerRestarting() { - peer.fsm.pConf.GracefulRestart.State.PeerRestarting = false - for _, ch := range peer.llgrEndChs { - close(ch) - } - peer.llgrEndChs = make([]chan struct{}, 0) - -} - -func (peer *Peer) filterPathFromSourcePeer(path, old *table.Path) *table.Path { - if peer.ID() != path.GetSource().Address.String() { - return path - } - - // Note: Multiple paths having the same prefix could exist the withdrawals - // list in the case of Route Server setup with import policies modifying - // paths. In such case, gobgp sends duplicated update messages; withdraw - // messages for the same prefix. - if !peer.isRouteServerClient() { - if peer.isRouteReflectorClient() && path.GetRouteFamily() == bgp.RF_RTC_UC { - // When the peer is a Route Reflector client and the given path - // contains the Route Tartget Membership NLRI, the path should not - // be withdrawn in order to signal the client to distribute routes - // with the specific RT to Route Reflector. - return path - } else if !path.IsWithdraw && old != nil && old.GetSource().Address.String() != peer.ID() { - // Say, peer A and B advertized same prefix P, and best path - // calculation chose a path from B as best. When B withdraws prefix - // P, best path calculation chooses the path from A as best. For - // peers other than A, this path should be advertised (as implicit - // withdrawal). However for A, we should advertise the withdrawal - // path. Thing is same when peer A and we advertized prefix P (as - // local route), then, we withdraws the prefix. - return old.Clone(true) - } - } - log.WithFields(log.Fields{ - "Topic": "Peer", - "Key": peer.ID(), - "Data": path, - }).Debug("From me, ignore.") - return nil -} - -func (peer *Peer) doPrefixLimit(k bgp.RouteFamily, c *config.PrefixLimitConfig) *bgp.BGPMessage { - if maxPrefixes := int(c.MaxPrefixes); maxPrefixes > 0 { - count := peer.adjRibIn.Count([]bgp.RouteFamily{k}) - pct := int(c.ShutdownThresholdPct) - if pct > 0 && !peer.prefixLimitWarned[k] && count > (maxPrefixes*pct/100) { - peer.prefixLimitWarned[k] = true - log.WithFields(log.Fields{ - "Topic": "Peer", - "Key": peer.ID(), - "AddressFamily": k.String(), - }).Warnf("prefix limit %d%% reached", pct) - } - if count > maxPrefixes { - log.WithFields(log.Fields{ - "Topic": "Peer", - "Key": peer.ID(), - "AddressFamily": k.String(), - }).Warnf("prefix limit reached") - return bgp.NewBGPNotificationMessage(bgp.BGP_ERROR_CEASE, bgp.BGP_ERROR_SUB_MAXIMUM_NUMBER_OF_PREFIXES_REACHED, nil) - } - } - return nil - -} - -func (peer *Peer) updatePrefixLimitConfig(c []config.AfiSafi) error { - x := peer.fsm.pConf.AfiSafis - y := c - if len(x) != len(y) { - return fmt.Errorf("changing supported afi-safi is not allowed") - } - m := make(map[bgp.RouteFamily]config.PrefixLimitConfig) - for _, e := range x { - m[e.State.Family] = e.PrefixLimit.Config - } - for _, e := range y { - if p, ok := m[e.State.Family]; !ok { - return fmt.Errorf("changing supported afi-safi is not allowed") - } else if !p.Equal(&e.PrefixLimit.Config) { - log.WithFields(log.Fields{ - "Topic": "Peer", - "Key": peer.ID(), - "AddressFamily": e.Config.AfiSafiName, - "OldMaxPrefixes": p.MaxPrefixes, - "NewMaxPrefixes": e.PrefixLimit.Config.MaxPrefixes, - "OldShutdownThresholdPct": p.ShutdownThresholdPct, - "NewShutdownThresholdPct": e.PrefixLimit.Config.ShutdownThresholdPct, - }).Warnf("update prefix limit configuration") - peer.prefixLimitWarned[e.State.Family] = false - if msg := peer.doPrefixLimit(e.State.Family, &e.PrefixLimit.Config); msg != nil { - sendFsmOutgoingMsg(peer, nil, msg, true) - } - } - } - peer.fsm.pConf.AfiSafis = c - return nil -} - -func (peer *Peer) handleUpdate(e *FsmMsg) ([]*table.Path, []bgp.RouteFamily, *bgp.BGPMessage) { - m := e.MsgData.(*bgp.BGPMessage) - update := m.Body.(*bgp.BGPUpdate) - log.WithFields(log.Fields{ - "Topic": "Peer", - "Key": peer.fsm.pConf.State.NeighborAddress, - "nlri": update.NLRI, - "withdrawals": update.WithdrawnRoutes, - "attributes": update.PathAttributes, - }).Debug("received update") - peer.fsm.pConf.Timers.State.UpdateRecvTime = time.Now().Unix() - if len(e.PathList) > 0 { - paths := make([]*table.Path, 0, len(e.PathList)) - eor := []bgp.RouteFamily{} - for _, path := range e.PathList { - if path.IsEOR() { - family := path.GetRouteFamily() - log.WithFields(log.Fields{ - "Topic": "Peer", - "Key": peer.ID(), - "AddressFamily": family, - }).Debug("EOR received") - eor = append(eor, family) - continue - } - // 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. - if aspath := path.GetAsPath(); aspath != nil { - if hasOwnASLoop(peer.fsm.peerInfo.LocalAS, int(peer.fsm.pConf.AsPathOptions.Config.AllowOwnAs), aspath) { - path.SetAsLooped(true) - continue - } - } - paths = append(paths, path) - } - peer.adjRibIn.Update(e.PathList) - for _, af := range peer.fsm.pConf.AfiSafis { - if msg := peer.doPrefixLimit(af.State.Family, &af.PrefixLimit.Config); msg != nil { - return nil, nil, msg - } - } - return paths, eor, nil - } - return nil, nil, nil -} - -func (peer *Peer) startFSMHandler(incoming *channels.InfiniteChannel, stateCh chan *FsmMsg) { - peer.fsm.h = NewFSMHandler(peer.fsm, incoming, stateCh, peer.outgoing) -} - -func (peer *Peer) StaleAll(rfList []bgp.RouteFamily) []*table.Path { - return peer.adjRibIn.StaleAll(rfList) -} - -func (peer *Peer) PassConn(conn *net.TCPConn) { - select { - case peer.fsm.connCh <- conn: - default: - conn.Close() - log.WithFields(log.Fields{ - "Topic": "Peer", - "Key": peer.ID(), - }).Warn("accepted conn is closed to avoid be blocked") - } -} - -func (peer *Peer) DropAll(rfList []bgp.RouteFamily) { - peer.adjRibIn.Drop(rfList) -} - -func (peer *Peer) stopFSM() error { - failed := false - addr := peer.fsm.pConf.State.NeighborAddress - t1 := time.AfterFunc(time.Minute*5, func() { - log.WithFields(log.Fields{ - "Topic": "Peer", - }).Warnf("Failed to free the fsm.h.t for %s", addr) - failed = true - }) - peer.fsm.h.t.Kill(nil) - peer.fsm.h.t.Wait() - t1.Stop() - if !failed { - log.WithFields(log.Fields{ - "Topic": "Peer", - "Key": addr, - }).Debug("freed fsm.h.t") - cleanInfiniteChannel(peer.outgoing) - } - failed = false - t2 := time.AfterFunc(time.Minute*5, func() { - log.WithFields(log.Fields{ - "Topic": "Peer", - }).Warnf("Failed to free the fsm.t for %s", addr) - failed = true - }) - peer.fsm.t.Kill(nil) - peer.fsm.t.Wait() - t2.Stop() - if !failed { - log.WithFields(log.Fields{ - "Topic": "Peer", - "Key": addr, - }).Debug("freed fsm.t") - return nil - } - return fmt.Errorf("Failed to free FSM for %s", addr) -} |