diff options
Diffstat (limited to 'server/peer.go')
-rw-r--r-- | server/peer.go | 181 |
1 files changed, 168 insertions, 13 deletions
diff --git a/server/peer.go b/server/peer.go index d76dd088..33ec9103 100644 --- a/server/peer.go +++ b/server/peer.go @@ -21,6 +21,7 @@ import ( "github.com/osrg/gobgp/api" "github.com/osrg/gobgp/config" "github.com/osrg/gobgp/packet" + "github.com/osrg/gobgp/policy" "github.com/osrg/gobgp/table" "gopkg.in/tomb.v2" "net" @@ -57,16 +58,20 @@ type Peer struct { adjRib *table.AdjRib // peer and rib are always not one-to-one so should not be // here but it's the simplest and works our first target. - rib *table.TableManager - isGlobalRib bool - rfMap map[bgp.RouteFamily]bool - capMap map[bgp.BGPCapabilityCode]bgp.ParameterCapabilityInterface - peerInfo *table.PeerInfo - siblings map[string]*serverMsgDataPeer - outgoing chan *bgp.BGPMessage + rib *table.TableManager + isGlobalRib bool + rfMap map[bgp.RouteFamily]bool + capMap map[bgp.BGPCapabilityCode]bgp.ParameterCapabilityInterface + peerInfo *table.PeerInfo + siblings map[string]*serverMsgDataPeer + outgoing chan *bgp.BGPMessage + importPolicies []*policy.Policy + defaultImportPolicy config.DefaultPolicyType + exportPolicies []*policy.Policy + defaultExportPolicy config.DefaultPolicyType } -func NewPeer(g config.Global, peer config.Neighbor, serverMsgCh chan *serverMsg, peerMsgCh chan *peerMsg, peerList []*serverMsgDataPeer, isGlobalRib bool) *Peer { +func NewPeer(g config.Global, peer config.Neighbor, serverMsgCh chan *serverMsg, peerMsgCh chan *peerMsg, peerList []*serverMsgDataPeer, isGlobalRib bool, policyMap map[string]*policy.Policy) *Peer { p := &Peer{ globalConfig: g, peerConfig: peer, @@ -96,10 +101,40 @@ func NewPeer(g config.Global, peer config.Neighbor, serverMsgCh chan *serverMsg, rfList := p.configuredRFlist() p.adjRib = table.NewAdjRib(rfList) p.rib = table.NewTableManager(p.peerConfig.NeighborAddress.String(), rfList) + p.setPolicy(policyMap) p.t.Go(p.loop) return p } +func (peer *Peer) setPolicy(policyMap map[string]*policy.Policy) { + // configure import policy + policyConfig := peer.peerConfig.ApplyPolicy + inPolicies := make([]*policy.Policy, 0) + for _, policyName := range policyConfig.ImportPolicies { + log.WithFields(log.Fields{ + "Topic": "Peer", + "Key": peer.peerConfig.NeighborAddress, + "PolicyName": policyName, + }).Info("import policy installed") + log.Debug("import policy : ", policyMap[policyName]) + inPolicies = append(inPolicies, policyMap[policyName]) + } + peer.importPolicies = inPolicies + + // configure export policy + outPolicies := make([]*policy.Policy, 0) + for _, policyName := range policyConfig.ExportPolicies { + log.WithFields(log.Fields{ + "Topic": "Peer", + "Key": peer.peerConfig.NeighborAddress, + "PolicyName": policyName, + }).Info("export policy installed") + log.Debug("export policy : ", policyMap[policyName]) + outPolicies = append(outPolicies, policyMap[policyName]) + } + peer.exportPolicies = outPolicies +} + func (peer *Peer) configuredRFlist() []bgp.RouteFamily { rfList := []bgp.RouteFamily{} for _, rf := range peer.peerConfig.AfiSafiList { @@ -317,9 +352,44 @@ func (peer *Peer) handleREST(restReq *api.RestRequest) { func (peer *Peer) sendUpdateMsgFromPaths(pList []table.Path) { pList = table.CloneAndUpdatePathAttrs(pList, &peer.globalConfig, &peer.peerConfig) - peer.adjRib.UpdateOut(pList) - sendpathList := []table.Path{} + paths := []table.Path{} + policies := peer.exportPolicies + log.WithFields(log.Fields{ + "Topic": "Peer", + "Key": peer.peerConfig.NeighborAddress, + }).Debug("Export Policies :", policies) for _, p := range pList { + if p.IsWithdraw() { + paths = append(paths, p) + continue + } + log.Debug("p: ", p) + if len(policies) != 0 { + applied, newPath := applyPolicies(policies, &p) + + if applied { + if newPath != nil { + log.Debug("path accepted") + paths = append(paths, *newPath) + } else { + log.Debug("path was rejected: ", p) + } + + } else { + if peer.defaultExportPolicy == config.DEFAULT_POLICY_TYPE_ACCEPT_ROUTE { + paths = append(paths, p) + log.Debug("path is emitted by default export policy: ", p) + } + } + } else { + paths = append(paths, p) + } + + } + + peer.adjRib.UpdateOut(paths) + sendpathList := []table.Path{} + for _, p := range paths { _, ok := peer.rfMap[p.GetRouteFamily()] if peer.peerConfig.NeighborAddress.Equal(p.GetNexthop()) { @@ -337,18 +407,99 @@ func (peer *Peer) sendUpdateMsgFromPaths(pList []table.Path) { peer.sendMessages(table.CreateUpdateMsgFromPaths(sendpathList)) } +// apply policies to the path +// if multiple policies are defined, +// this function applies each policy to the path in the order that +// policies are stored in the array passed to this function. +// +// the way of applying statements inside a single policy +// - apply statement until the condition in the statement matches. +// if the condition matches the path, apply the action on the statement and +// return value that indicates 'applied' to caller of this function +// - if no statement applied, then process the next policy +// +// if no policy applied, return value that indicates 'not applied' to the caller of this function +// +// return values: +// bool -- indicates that any of policy applied to the path that is passed to this function +// table.Path -- indicates new path object that is the result of modification according to +// policy's action. +// If the applied policy doesn't have a modification action, +// then return the path itself that is passed to this function, otherwise return +// modified path. +// If action of the policy is 'reject', return nil +// +func applyPolicies(policies []*policy.Policy, original *table.Path) (bool, *table.Path) { + + var applied bool = true + + for _, pol := range policies { + if result, action, newpath := pol.Apply(*original); result { + log.Debug("newpath: ", newpath) + if action == policy.ROUTE_TYPE_REJECT { + log.Debug("path was rejected: ", original) + // return applied, nil, this means path was rejected + return applied, nil + } else { + // return applied, new path + return applied, &newpath + } + } + } + log.Debug("no policy applied.", original) + // return not applied, original path + return !applied, original +} + func (peer *Peer) handlePeerMsg(m *peerMsg) { switch m.msgType { case PEER_MSG_PATH: pList := m.msgData.([]table.Path) + paths := []table.Path{} + + policies := peer.importPolicies + log.WithFields(log.Fields{ + "Topic": "Peer", + "Key": peer.peerConfig.NeighborAddress, + }).Debug("Import Policies :", policies) + + for _, p := range pList { + log.Debug("p: ", p) + if !p.IsWithdraw() { + log.Debug("is not withdraw") + + if len(policies) != 0 { + applied, newPath := applyPolicies(policies, &p) + + if applied { + if newPath != nil { + log.Debug("path accepted") + paths = append(paths, *newPath) + } + } else { + if peer.defaultImportPolicy == config.DEFAULT_POLICY_TYPE_ACCEPT_ROUTE { + paths = append(paths, p) + log.Debug("path accepted by default import policy: ", p) + } + } + } else { + paths = append(paths, p) + } + } else { + log.Debug("is withdraw") + paths = append(paths, p) + } + } + log.Debug("length of paths: ", len(paths)) + if peer.peerConfig.RouteServer.RouteServerClient || peer.isGlobalRib { - pList, _ = peer.rib.ProcessPaths(pList) + paths, _ = peer.rib.ProcessPaths(paths) } if peer.isGlobalRib { - peer.sendPathsToSiblings(pList) + peer.sendPathsToSiblings(paths) } else { - peer.sendUpdateMsgFromPaths(pList) + peer.sendUpdateMsgFromPaths(paths) } case PEER_MSG_PEER_DOWN: @@ -392,6 +543,10 @@ func (peer *Peer) handleServerMsg(m *serverMsg) { } case SRV_MSG_API: peer.handleREST(m.msgData.(*api.RestRequest)) + case SRV_MSG_POLICY_UPDATED: + log.Debug("policy updated") + d := m.msgData.(map[string]*policy.Policy) + peer.setPolicy(d) default: log.Fatal("unknown server msg type ", m.msgType) } |