diff options
author | Hiroshi Yokoi <yokoi.hiroshi@po.ntts.co.jp> | 2015-03-24 22:11:27 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2015-03-24 22:11:27 +0900 |
commit | 38bb94707f35e103db3b313978bcac4046f99a20 (patch) | |
tree | 6f740cfc751931fc47c223c39ce7dfeaa87fe1e7 | |
parent | 8fb175eb2c3079613a7970e85d1648207c9d829b (diff) |
policy: apply import/export policy
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r-- | bgpd.go | 22 | ||||
-rw-r--r-- | config/serve.go | 37 | ||||
-rw-r--r-- | policy/policy.go | 249 | ||||
-rw-r--r-- | policy/policy_test.go | 31 | ||||
-rw-r--r-- | server/peer.go | 181 | ||||
-rw-r--r-- | server/server.go | 51 |
6 files changed, 427 insertions, 144 deletions
@@ -136,11 +136,10 @@ func main() { opts.ConfigFile = "gobgpd.conf" } - configCh := make(chan config.Bgp) + configCh := make(chan config.BgpConfigSet) reloadCh := make(chan bool) go config.ReadConfigfileServe(opts.ConfigFile, configCh, reloadCh) reloadCh <- true - bgpServer := server.NewBgpServer(bgp.BGP_PORT) go bgpServer.Serve() @@ -149,6 +148,7 @@ func main() { go restServer.Serve() var bgpConfig *config.Bgp = nil + var policyConfig *config.RoutingPolicy = nil for { select { case newConfig := <-configCh: @@ -156,12 +156,22 @@ func main() { var deleted []config.Neighbor if bgpConfig == nil { - bgpServer.SetGlobalType(newConfig.Global) - bgpConfig = &newConfig - added = newConfig.NeighborList + bgpServer.SetGlobalType(newConfig.Bgp.Global) + bgpConfig = &newConfig.Bgp + added = newConfig.Bgp.NeighborList deleted = []config.Neighbor{} } else { - bgpConfig, added, deleted = config.UpdateConfig(bgpConfig, &newConfig) + bgpConfig, added, deleted = config.UpdateConfig(bgpConfig, &newConfig.Bgp) + } + + if policyConfig == nil { + policyConfig = &newConfig.Policy + bgpServer.SetPolicy(newConfig.Policy) + } else { + if res := config.CheckPolicyDifference(policyConfig, &newConfig.Policy); res { + log.Info("Policy config is updated") + bgpServer.UpdatePolicy(newConfig.Policy) + } } for _, p := range added { diff --git a/config/serve.go b/config/serve.go index 6832f6b4..390229c1 100644 --- a/config/serve.go +++ b/config/serve.go @@ -3,9 +3,15 @@ package config import ( "github.com/BurntSushi/toml" log "github.com/Sirupsen/logrus" + "reflect" ) -func ReadConfigfileServe(path string, configCh chan Bgp, reloadCh chan bool) { +type BgpConfigSet struct { + Bgp Bgp + Policy RoutingPolicy +} + +func ReadConfigfileServe(path string, configCh chan BgpConfigSet, reloadCh chan bool) { for { <-reloadCh @@ -18,7 +24,14 @@ func ReadConfigfileServe(path string, configCh chan Bgp, reloadCh chan bool) { log.Fatal("can't read config file ", path, ", ", err) } - configCh <- b + p := RoutingPolicy{} + md, err = toml.DecodeFile(path, &p) + if err != nil { + log.Fatal("can't read config file ", path, ", ", err) + } + + bgpConfig := BgpConfigSet{Bgp: b, Policy: p} + configCh <- bgpConfig } } @@ -58,3 +71,23 @@ func UpdateConfig(curC *Bgp, newC *Bgp) (*Bgp, []Neighbor, []Neighbor) { bgpConfig.NeighborList = newC.NeighborList return &bgpConfig, added, deleted } + +func CheckPolicyDifference(currentPolicy *RoutingPolicy, newPolicy *RoutingPolicy) bool { + + log.Debug("current policy : ", currentPolicy) + log.Debug("newPolicy policy : ", newPolicy) + + var result bool = false + if currentPolicy == nil && newPolicy == nil { + + result = false + } else { + if currentPolicy != nil && newPolicy != nil { + // TODO: reconsider the way of policy object comparison + result = !reflect.DeepEqual(*currentPolicy, *newPolicy) + } else { + result = true + } + } + return result +} diff --git a/policy/policy.go b/policy/policy.go index 9bb4bc8c..fe1eb79c 100644 --- a/policy/policy.go +++ b/policy/policy.go @@ -37,7 +37,7 @@ const ( type MaskLengthRangeType int const ( - MASK_LENGTH_RANGE_MIN = iota + MASK_LENGTH_RANGE_MIN MaskLengthRangeType = iota MASK_LENGTH_RANGE_MAX ) @@ -46,42 +46,48 @@ type Policy struct { Statements []Statement } -func NewPolicy(name string, pd config.PolicyDefinition, cdf config.DefinedSets) *Policy { - cst := pd.StatementList +func NewPolicy(name string, pd config.PolicyDefinition, ds config.DefinedSets) *Policy { + stmtList := pd.StatementList st := make([]Statement, 0) p := &Policy{ - Name: name, - Statements: st, + Name: name, } - for _, cs := range cst { - pName := cs.Conditions.MatchPrefixSet - npl := make([]Prefix, 0) - for _, psl := range cdf.PrefixSetList { - if psl.PrefixSetName == pName { - for _, ps := range psl.PrefixList { - npl = append(npl, NewPrefix(ps.Address, ps.Masklength, ps.MasklengthRange)) + for _, statement := range stmtList { + prefixSetName := statement.Conditions.MatchPrefixSet + + prefixList := make([]Prefix, 0) + for _, ps := range ds.PrefixSetList { + if ps.PrefixSetName == prefixSetName { + for _, pl := range ps.PrefixList { + prefixList = append(prefixList, NewPrefix(pl.Address, pl.Masklength, pl.MasklengthRange)) } } } - nName := cs.Conditions.MatchNeighborSet - nnl := make([]net.IP, 0) - for _, nsl := range cdf.NeighborSetList { - if nsl.NeighborSetName == nName { - for _, nl := range nsl.NeighborInfoList { - nnl = append(nnl, nl.Address) + + neighborSetName := statement.Conditions.MatchNeighborSet + neighborList := make([]net.IP, 0) + for _, neighborSet := range ds.NeighborSetList { + if neighborSet.NeighborSetName == neighborSetName { + for _, nl := range neighborSet.NeighborInfoList { + neighborList = append(neighborList, nl.Address) } } } - con := Conditions{ - PrefixList: npl, - NeighborList: nnl, + con := &PrefixConditions{ + PrefixList: prefixList, + NeighborList: neighborList, + MatchSetOptions: statement.Conditions.MatchSetOptions, } - act := Actions{ - AcceptRoute: cs.Actions.AcceptRoute, - RejectRoute: cs.Actions.RejectRoute, + + act := &RoutingActions{ + AcceptRoute: false, } + if statement.Actions.AcceptRoute { + act.AcceptRoute = true + } + s := Statement{ - Name: cs.Name, + Name: statement.Name, Conditions: con, Actions: act, } @@ -97,15 +103,109 @@ type Statement struct { Actions Actions } -type Conditions struct { - //CallPolicy string - PrefixList []Prefix - NeighborList []net.IP +type Conditions interface { + evaluate(table.Path) bool +} + +type DefaultConditions struct { + CallPolicy string +} + +func (c *DefaultConditions) evaluate(path table.Path) bool { + return false +} + +type PrefixConditions struct { + DefaultConditions + PrefixList []Prefix + NeighborList []net.IP + MatchSetOptions config.MatchSetOptionsType +} + +// evaluate path's prefix and neighbor's address with conditions +// return value depends on MatchSetOptions +func (c *PrefixConditions) evaluate(path table.Path) bool { + pref := c.evaluatePrefix(path) + log.Debug("evaluate prefix : ", pref) + neigh := c.evaluateNeighbor(path) + log.Debug("evaluate neighbor : ", neigh) + + switch c.MatchSetOptions { + case config.MATCH_SET_OPTIONS_TYPE_ALL: + return pref && neigh + case config.MATCH_SET_OPTIONS_TYPE_ANY: + return pref || neigh + case config.MATCH_SET_OPTIONS_TYPE_INVERT: + return !(pref || neigh) + default: + return false + } +} + +// compare prefixes in this condition and nlri of path and +// subsequent comparison is skipped if that matches the conditions. +// If PrefixList's length is zero, return true. +func (c *PrefixConditions) evaluatePrefix(path table.Path) bool { + + if len(c.PrefixList) == 0 { + return true + } + + for _, cp := range c.PrefixList { + if IpPrefixCalculate(path, cp) { + return true + } + } + return false +} + +// compare neighbor ipaddress of this condition and source address of path +// and, subsequent comparisons are skipped if that matches the conditions. +// If NeighborList's length is zero, return true. +func (c *PrefixConditions) evaluateNeighbor(path table.Path) bool { + + if len(c.NeighborList) == 0 { + return true + } + + for _, neighbor := range c.NeighborList { + cAddr := neighbor + pAddr := path.GetSource().Address + if pAddr.Equal(cAddr) { + return true + } + } + return false +} + +type Actions interface { + apply(table.Path) table.Path +} + +type DefaultActions struct { +} + +func (a *DefaultActions) apply(path table.Path) table.Path { + return path } -type Actions struct { +type RoutingActions struct { + DefaultActions AcceptRoute bool - RejectRoute bool +} + +func (r *RoutingActions) apply(path table.Path) table.Path { + if r.AcceptRoute { + return path + } else { + return nil + } +} + +type ModificationActions struct { + DefaultActions + AttrType bgp.BGPAttrType + Value string } type Prefix struct { @@ -121,13 +221,16 @@ func NewPrefix(addr net.IP, maskLen uint8, maskRange string) Prefix { Masklength: maskLen, MasklengthRange: make(map[MaskLengthRangeType]uint8), } + + // TODO: validate mask length by using regexp + idx := strings.Index(maskRange, "..") if idx == -1 { log.WithFields(log.Fields{ "Topic": "Policy", "Address": addr, "Masklength": maskLen, - }).Warn("mask length range of condition is invalid format") + }).Warn("mask length range of condition is invalid format. mask length is not defined.") return p } if idx != 0 { @@ -160,51 +263,20 @@ func NewPrefix(addr net.IP, maskLen uint8, maskRange string) Prefix { //and, subsequent comparison skip if that matches the conditions. func (p *Policy) Apply(path table.Path) (bool, RouteType, table.Path) { for _, statement := range p.Statements { - matchPrefix := false - matchNeighbor := false - if len(statement.Conditions.PrefixList) <= 0 && len(statement.Conditions.NeighborList) <= 0 { - return false, ROUTE_TYPE_NONE, nil - } else if len(statement.Conditions.PrefixList) <= 0 && len(statement.Conditions.NeighborList) > 0 { - matchPrefix = true - matchNeighbor = statement.compareNeighbor(path) - } else if len(statement.Conditions.NeighborList) <= 0 && len(statement.Conditions.PrefixList) > 0 { - matchPrefix = statement.comparePrefix(path) - matchNeighbor = true - } else { - matchPrefix = statement.comparePrefix(path) - matchNeighbor = statement.compareNeighbor(path) - } - an := statement.Actions - - //if match the one of the prefix list and match to any of tye neighbor list, - //determines that matches the conditions of the statement - if matchPrefix && matchNeighbor { - if an.AcceptRoute { - // accept the path - // and return the path updated in acction definition - // TODO update path using acction definition. - // implementation waiting for yang. - newPath := path - log.WithFields(log.Fields{ - "Topic": "Policy", - "Type": "ROUTE_ACCEPT", - "OldPath": path, - "NewPath": newPath, - }).Debug("Apply policy to path") - return true, ROUTE_TYPE_ACCEPT, newPath + result := statement.Conditions.evaluate(path) + log.WithFields(log.Fields{ + "Topic": "Policy", + "Path": path, + "PolicyName": p.Name, + }).Debug("statement.Conditions.evaluate : ", result) + + var p table.Path + if result { + p = statement.Actions.apply(path) + if p != nil { + return true, ROUTE_TYPE_ACCEPT, p } else { - // reject the path - // and return the path updated in acction definition - // TODO update path using acction definition. - // implementation waiting for yang. - newPath := path - log.WithFields(log.Fields{ - "Topic": "Policy", - "Type": "ROUTE_REJECT", - "OldPath": path, - "NewPath": newPath, - }).Debug("Apply policy to path") return true, ROUTE_TYPE_REJECT, nil } } @@ -212,32 +284,7 @@ func (p *Policy) Apply(path table.Path) (bool, RouteType, table.Path) { return false, ROUTE_TYPE_NONE, nil } -//compare prefix of condition policy and nlri of path -//and, subsequent comparison skip if that matches the conditions. -func (s *Statement) comparePrefix(path table.Path) bool { - for _, cp := range s.Conditions.PrefixList { - if IpPrefixCalcurate(path, cp) { - return true - } - } - return false -} - -//compare neighbor ipaddress of condition policy and source of path -//and, subsequent comparison skip if that matches the conditions. -func (s *Statement) compareNeighbor(path table.Path) bool { - for _, neighbor := range s.Conditions.NeighborList { - cAddr := neighbor - pAddr := path.GetSource().Address - if pAddr.Equal(cAddr) { - return true - } - - } - return false -} - -func IpPrefixCalcurate(path table.Path, cPrefix Prefix) bool { +func IpPrefixCalculate(path table.Path, cPrefix Prefix) bool { pAddr := path.GetNlri().(*bgp.NLRInfo).IPAddrPrefix.Prefix pMaskLen := path.GetNlri().(*bgp.NLRInfo).IPAddrPrefix.Length cp := fmt.Sprintf("%s/%d", cPrefix.Address, cPrefix.Masklength) diff --git a/policy/policy_test.go b/policy/policy_test.go index 34c6c5ef..212371b8 100644 --- a/policy/policy_test.go +++ b/policy/policy_test.go @@ -16,6 +16,7 @@ package policy import ( + log "github.com/Sirupsen/logrus" "github.com/osrg/gobgp/config" "github.com/osrg/gobgp/packet" "github.com/osrg/gobgp/table" @@ -25,6 +26,7 @@ import ( ) func TestPrefixCalcurateNoRange(t *testing.T) { + log.SetLevel(log.DebugLevel) // creatae path peer := &table.PeerInfo{AS: 65001, Address: net.ParseIP("10.0.0.1")} origin := bgp.NewPathAttributeOrigin(0) @@ -40,13 +42,13 @@ func TestPrefixCalcurateNoRange(t *testing.T) { path := msg.ToPathList()[0] // test pl1 := NewPrefix(net.ParseIP("10.10.0.0"), 24, "") - match1 := IpPrefixCalcurate(path, pl1) + match1 := IpPrefixCalculate(path, pl1) assert.Equal(t, match1, false) pl2 := NewPrefix(net.ParseIP("10.10.0.101"), 24, "") - match2 := IpPrefixCalcurate(path, pl2) + match2 := IpPrefixCalculate(path, pl2) assert.Equal(t, match2, true) pl3 := NewPrefix(net.ParseIP("10.10.0.0"), 16, "21..24") - match3 := IpPrefixCalcurate(path, pl3) + match3 := IpPrefixCalculate(path, pl3) assert.Equal(t, match3, true) } @@ -66,10 +68,10 @@ func TestPrefixCalcurateInAddress(t *testing.T) { path := msg.ToPathList()[0] // test pl1 := NewPrefix(net.ParseIP("10.11.0.0"), 16, "21..24") - match1 := IpPrefixCalcurate(path, pl1) + match1 := IpPrefixCalculate(path, pl1) assert.Equal(t, match1, false) pl2 := NewPrefix(net.ParseIP("10.10.0.0"), 16, "21..24") - match2 := IpPrefixCalcurate(path, pl2) + match2 := IpPrefixCalculate(path, pl2) assert.Equal(t, match2, true) } @@ -89,10 +91,10 @@ func TestPrefixCalcurateInLength(t *testing.T) { path := msg.ToPathList()[0] // test pl1 := NewPrefix(net.ParseIP("10.10.64.0"), 24, "21..24") - match1 := IpPrefixCalcurate(path, pl1) + match1 := IpPrefixCalculate(path, pl1) assert.Equal(t, match1, false) pl2 := NewPrefix(net.ParseIP("10.10.64.0"), 16, "21..24") - match2 := IpPrefixCalcurate(path, pl2) + match2 := IpPrefixCalculate(path, pl2) assert.Equal(t, match2, true) } @@ -112,13 +114,13 @@ func TestPrefixCalcurateInLengthRange(t *testing.T) { path := msg.ToPathList()[0] // test pl1 := NewPrefix(net.ParseIP("10.10.0.0"), 16, "21..23") - match1 := IpPrefixCalcurate(path, pl1) + match1 := IpPrefixCalculate(path, pl1) assert.Equal(t, match1, false) pl2 := NewPrefix(net.ParseIP("10.10.0.0"), 16, "25..26") - match2 := IpPrefixCalcurate(path, pl2) + match2 := IpPrefixCalculate(path, pl2) assert.Equal(t, match2, false) pl3 := NewPrefix(net.ParseIP("10.10.0.0"), 16, "21..24") - match3 := IpPrefixCalcurate(path, pl3) + match3 := IpPrefixCalculate(path, pl3) assert.Equal(t, match3, true) } @@ -162,6 +164,7 @@ func TestPolicyNotMatchL(t *testing.T) { Conditions: config.Conditions{ MatchPrefixSet: "ps1", MatchNeighborSet: "ns1", + MatchSetOptions: config.MATCH_SET_OPTIONS_TYPE_ALL, }, Actions: config.Actions{ AcceptRoute: false, @@ -220,6 +223,7 @@ func TestPolicyMatchAndReject(t *testing.T) { Conditions: config.Conditions{ MatchPrefixSet: "ps1", MatchNeighborSet: "ns1", + MatchSetOptions: config.MATCH_SET_OPTIONS_TYPE_ALL, }, Actions: config.Actions{ AcceptRoute: false, @@ -278,6 +282,7 @@ func TestPolicyMatchAndAccept(t *testing.T) { Conditions: config.Conditions{ MatchPrefixSet: "ps1", MatchNeighborSet: "ns1", + MatchSetOptions: config.MATCH_SET_OPTIONS_TYPE_ALL, }, Actions: config.Actions{ AcceptRoute: true, @@ -318,7 +323,7 @@ func TestPolicyRejectOnlyPrefixList(t *testing.T) { nexthop = bgp.NewPathAttributeNextHop("10.0.2.2") med = bgp.NewPathAttributeMultiExitDisc(0) pathAttributes = []bgp.PathAttributeInterface{origin, aspath, nexthop, med} - nlri = []bgp.NLRInfo{*bgp.NewNLRInfo(24, "10.10.2.102")} + nlri = []bgp.NLRInfo{*bgp.NewNLRInfo(24, "10.9.2.102")} withdrawnRoutes = []bgp.WithdrawnRoute{} updateMsg = bgp.NewBGPUpdateMessage(withdrawnRoutes, pathAttributes, nlri) msg = table.NewProcessMessage(updateMsg, peer) @@ -330,7 +335,7 @@ func TestPolicyRejectOnlyPrefixList(t *testing.T) { PrefixList: []config.Prefix{ config.Prefix{ Address: net.ParseIP("10.10.1.0"), - Masklength: 24, + Masklength: 16, MasklengthRange: "21..24", }}, } @@ -343,6 +348,7 @@ func TestPolicyRejectOnlyPrefixList(t *testing.T) { Conditions: config.Conditions{ MatchPrefixSet: "ps1", MatchNeighborSet: "ns1", + MatchSetOptions: config.MATCH_SET_OPTIONS_TYPE_ALL, }, Actions: config.Actions{ AcceptRoute: false, @@ -411,6 +417,7 @@ func TestPolicyRejectOnlyNeighborList(t *testing.T) { Conditions: config.Conditions{ MatchPrefixSet: "ps1", MatchNeighborSet: "ns1", + MatchSetOptions: config.MATCH_SET_OPTIONS_TYPE_ALL, }, Actions: config.Actions{ AcceptRoute: false, 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) } diff --git a/server/server.go b/server/server.go index 27570d5a..22fb48c3 100644 --- a/server/server.go +++ b/server/server.go @@ -21,6 +21,7 @@ import ( log "github.com/Sirupsen/logrus" "github.com/osrg/gobgp/api" "github.com/osrg/gobgp/config" + "github.com/osrg/gobgp/policy" "net" "os" "strconv" @@ -34,6 +35,7 @@ const ( SRV_MSG_PEER_ADDED SRV_MSG_PEER_DELETED SRV_MSG_API + SRV_MSG_POLICY_UPDATED ) type serverMsg struct { @@ -55,14 +57,16 @@ type peerMapInfo struct { } type BgpServer struct { - bgpConfig config.Bgp - globalTypeCh chan config.Global - addedPeerCh chan config.Neighbor - deletedPeerCh chan config.Neighbor - RestReqCh chan *api.RestRequest - listenPort int - peerMap map[string]peerMapInfo - globalRib *Peer + bgpConfig config.Bgp + globalTypeCh chan config.Global + addedPeerCh chan config.Neighbor + deletedPeerCh chan config.Neighbor + RestReqCh chan *api.RestRequest + listenPort int + peerMap map[string]peerMapInfo + globalRib *Peer + policyUpdateCh chan config.RoutingPolicy + policyMap map[string]*policy.Policy } func NewBgpServer(port int) *BgpServer { @@ -71,6 +75,7 @@ func NewBgpServer(port int) *BgpServer { b.addedPeerCh = make(chan config.Neighbor) b.deletedPeerCh = make(chan config.Neighbor) b.RestReqCh = make(chan *api.RestRequest, 1) + b.policyUpdateCh = make(chan config.RoutingPolicy) b.listenPort = port return &b } @@ -112,7 +117,7 @@ func (server *BgpServer) Serve() { NeighborAddress: g.RouterId, AfiSafiList: g.AfiSafiList, } - server.globalRib = NewPeer(g, neighConf, globalSch, globalPch, nil, true) + server.globalRib = NewPeer(g, neighConf, globalSch, globalPch, nil, true, make(map[string]*policy.Policy)) listenerMap := make(map[string]*net.TCPListener) acceptCh := make(chan *net.TCPConn) @@ -175,7 +180,7 @@ func (server *BgpServer) Serve() { } l = []*serverMsgDataPeer{globalRib} } - p := NewPeer(server.bgpConfig.Global, peer, sch, pch, l, false) + p := NewPeer(server.bgpConfig.Global, peer, sch, pch, l, false, server.policyMap) d := &serverMsgDataPeer{ address: peer.NeighborAddress, peerMsgCh: pch, @@ -219,10 +224,23 @@ func (server *BgpServer) Serve() { } case restReq := <-server.RestReqCh: server.handleRest(restReq) + case pl := <-server.policyUpdateCh: + server.SetPolicy(pl) + msg := &serverMsg{ + msgType: SRV_MSG_POLICY_UPDATED, + msgData: server.policyMap, + } + sendServerMsgToAll(server.peerMap, msg) } } } +func sendServerMsgToAll(peerMap map[string]peerMapInfo, msg *serverMsg) { + for _, info := range peerMap { + info.serverMsgCh <- msg + } +} + func sendServerMsgToRSClients(peerMap map[string]peerMapInfo, msg *serverMsg) { for _, info := range peerMap { if info.isRouteServerClient { @@ -243,6 +261,19 @@ func (server *BgpServer) PeerDelete(peer config.Neighbor) { server.deletedPeerCh <- peer } +func (server *BgpServer) UpdatePolicy(policy config.RoutingPolicy) { + server.policyUpdateCh <- policy +} + +func (server *BgpServer) SetPolicy(pl config.RoutingPolicy) { + pMap := make(map[string]*policy.Policy) + df := pl.DefinedSets + for _, p := range pl.PolicyDefinitionList { + pMap[p.Name] = policy.NewPolicy(p.Name, p, df) + } + server.policyMap = pMap +} + func (server *BgpServer) handleRest(restReq *api.RestRequest) { switch restReq.RequestType { case api.REQ_NEIGHBORS: |