summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--bgpd.go22
-rw-r--r--config/serve.go37
-rw-r--r--policy/policy.go249
-rw-r--r--policy/policy_test.go31
-rw-r--r--server/peer.go181
-rw-r--r--server/server.go51
6 files changed, 427 insertions, 144 deletions
diff --git a/bgpd.go b/bgpd.go
index 7053783b..090828eb 100644
--- a/bgpd.go
+++ b/bgpd.go
@@ -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: