diff options
author | Hiroshi Yokoi <yokoi.hiroshi@po.ntts.co.jp> | 2015-04-28 20:13:10 +0900 |
---|---|---|
committer | Hiroshi Yokoi <yokoi.hiroshi@po.ntts.co.jp> | 2015-04-30 15:52:05 +0900 |
commit | 483d37a1b4b5ea053ec7c95073b9f05a2152385f (patch) | |
tree | 24c92c8779db8073a31a533b63a77fd4930d6c5c | |
parent | f9577fe75336776c6113ae065062a2455193c798 (diff) |
policy: add AsPathLength match
-rw-r--r-- | policy/policy.go | 91 | ||||
-rw-r--r-- | policy/policy_test.go | 170 | ||||
-rw-r--r-- | table/path.go | 29 |
3 files changed, 261 insertions, 29 deletions
diff --git a/policy/policy.go b/policy/policy.go index 5a683e36..10ab0736 100644 --- a/policy/policy.go +++ b/policy/policy.go @@ -41,6 +41,17 @@ const ( MASK_LENGTH_RANGE_MAX ) +type AttributeComparison int + +const ( + // "== comparison" + ATTRIBUTE_EQ AttributeComparison = iota + // ">= comparison" + ATTRIBUTE_GE + // "<= comparison" + ATTRIBUTE_LE +) + type Policy struct { Name string Statements []*Statement @@ -55,7 +66,7 @@ func NewPolicy(name string, pd config.PolicyDefinition, ds config.DefinedSets) * for _, statement := range stmtList { - conditions := make([]Condition,0) + conditions := make([]Condition, 0) // prefix match prefixSetName := statement.Conditions.MatchPrefixSet @@ -67,6 +78,13 @@ func NewPolicy(name string, pd config.PolicyDefinition, ds config.DefinedSets) * nc := NewNeighborCondition(neighborSetName, ds.NeighborSetList) conditions = append(conditions, nc) + // AsPathLengthCondition + c := statement.Conditions.BgpConditions.AsPathLength + ac := NewAsPathLengthCondition(c) + if ac != nil { + conditions = append(conditions, ac) + } + action := &RoutingActions{ AcceptRoute: false, } @@ -76,9 +94,9 @@ func NewPolicy(name string, pd config.PolicyDefinition, ds config.DefinedSets) * } s := &Statement{ - Name: statement.Name, - Conditions: conditions, - Actions: action, + Name: statement.Name, + Conditions: conditions, + Actions: action, MatchSetOptions: statement.Conditions.MatchSetOptions, } @@ -169,7 +187,7 @@ func NewPrefixCondition(prefixSetName string, defPrefixList []config.PrefixSet) "Topic": "Policy", "prefix": prefix, "msg": e, - }).Warn("failed to generate a NewPrefix from configration.") + }).Error("failed to generate a NewPrefix from configration.") } else { prefixList = append(prefixList, prefix) } @@ -196,7 +214,7 @@ func (c *PrefixCondition) evaluate(path table.Path) bool { } for _, cp := range c.PrefixList { - if IpPrefixCalculate(path, cp) { + if ipPrefixCalculate(path, cp) { log.Debug("prefix matched : ", cp) return true } @@ -247,6 +265,60 @@ func (c *NeighborCondition) evaluate(path table.Path) bool { return false } +type AsPathLengthCondition struct { + DefaultCondition + Value uint32 + Operator AttributeComparison +} + +// create AsPathLengthCondition object +func NewAsPathLengthCondition(defAsPathLength config.AsPathLength) *AsPathLengthCondition { + + value := defAsPathLength.Value + var op AttributeComparison + + switch defAsPathLength.Operator { + case "eq": + op = ATTRIBUTE_EQ + + case "ge": + op = ATTRIBUTE_GE + + case "le": + op = ATTRIBUTE_LE + default: + return nil + } + + ac := &AsPathLengthCondition{ + Value: value, + Operator: op, + } + + return ac +} + +// compare AS_PATH length in the message's AS_PATH attribute with +// the one in condition. +func (c *AsPathLengthCondition) evaluate(path table.Path) bool { + + length := uint32(path.GetAsPathLen()) + + switch c.Operator { + case ATTRIBUTE_EQ: + return c.Value == length + + case ATTRIBUTE_GE: + return c.Value <= length + + case ATTRIBUTE_LE: + return c.Value >= length + default: + return false + } + +} + type Actions interface { apply(table.Path) table.Path } @@ -330,8 +402,9 @@ func NewPrefix(addr net.IP, maskLen uint8, maskRange string) (Prefix, error) { return p, nil } -//compare path and condition of policy -//and, subsequent comparison skip if that matches the conditions. +// Compare path with a policy's condition in stored order in the policy. +// If a condition match, then this function stops evaluation and +// subsequent conditions are skipped. func (p *Policy) Apply(path table.Path) (bool, RouteType, table.Path) { for _, statement := range p.Statements { @@ -355,7 +428,7 @@ func (p *Policy) Apply(path table.Path) (bool, RouteType, table.Path) { return false, ROUTE_TYPE_NONE, nil } -func IpPrefixCalculate(path table.Path, cPrefix Prefix) bool { +func ipPrefixCalculate(path table.Path, cPrefix Prefix) bool { rf := path.GetRouteFamily() log.Debug("path routefamily : ", rf.String()) var pAddr net.IP diff --git a/policy/policy_test.go b/policy/policy_test.go index 335f1a66..1f27fd4c 100644 --- a/policy/policy_test.go +++ b/policy/policy_test.go @@ -41,13 +41,13 @@ func TestPrefixCalcurateNoRange(t *testing.T) { path := table.ProcessMessage(updateMsg, peer)[0] // test pl1, _ := NewPrefix(net.ParseIP("10.10.0.0"), 24, "") - match1 := IpPrefixCalculate(path, pl1) + match1 := ipPrefixCalculate(path, pl1) assert.Equal(t, false, match1) pl2, _ := NewPrefix(net.ParseIP("10.10.0.101"), 24, "") - match2 := IpPrefixCalculate(path, pl2) + match2 := ipPrefixCalculate(path, pl2) assert.Equal(t, true, match2) pl3, _ := NewPrefix(net.ParseIP("10.10.0.0"), 16, "21..24") - match3 := IpPrefixCalculate(path, pl3) + match3 := ipPrefixCalculate(path, pl3) assert.Equal(t, true, match3) } @@ -66,10 +66,10 @@ func TestPrefixCalcurateAddress(t *testing.T) { path := table.ProcessMessage(updateMsg, peer)[0] // test pl1, _ := NewPrefix(net.ParseIP("10.11.0.0"), 16, "21..24") - match1 := IpPrefixCalculate(path, pl1) + match1 := ipPrefixCalculate(path, pl1) assert.Equal(t, false, match1) pl2, _ := NewPrefix(net.ParseIP("10.10.0.0"), 16, "21..24") - match2 := IpPrefixCalculate(path, pl2) + match2 := ipPrefixCalculate(path, pl2) assert.Equal(t, true, match2) } @@ -88,10 +88,10 @@ func TestPrefixCalcurateLength(t *testing.T) { path := table.ProcessMessage(updateMsg, peer)[0] // test pl1, _ := NewPrefix(net.ParseIP("10.10.64.0"), 24, "21..24") - match1 := IpPrefixCalculate(path, pl1) + match1 := ipPrefixCalculate(path, pl1) assert.Equal(t, false, match1) pl2, _ := NewPrefix(net.ParseIP("10.10.64.0"), 16, "21..24") - match2 := IpPrefixCalculate(path, pl2) + match2 := ipPrefixCalculate(path, pl2) assert.Equal(t, true, match2) } @@ -110,13 +110,13 @@ func TestPrefixCalcurateLengthRange(t *testing.T) { path := table.ProcessMessage(updateMsg, peer)[0] // test pl1, _ := NewPrefix(net.ParseIP("10.10.0.0"), 16, "21..23") - match1 := IpPrefixCalculate(path, pl1) + match1 := ipPrefixCalculate(path, pl1) assert.Equal(t, false, match1) pl2, _ := NewPrefix(net.ParseIP("10.10.0.0"), 16, "25..26") - match2 := IpPrefixCalculate(path, pl2) + match2 := ipPrefixCalculate(path, pl2) assert.Equal(t, false, match2) pl3, _ := NewPrefix(net.ParseIP("10.10.0.0"), 16, "21..24") - match3 := IpPrefixCalculate(path, pl3) + match3 := ipPrefixCalculate(path, pl3) assert.Equal(t, true, match3) } @@ -137,13 +137,13 @@ func TestPrefixCalcurateNoRangeIPv6(t *testing.T) { path := table.ProcessMessage(updateMsg, peer)[0] // test pl1, _ := NewPrefix(net.ParseIP("2001:123:123::"), 48, "") - match1 := IpPrefixCalculate(path, pl1) + match1 := ipPrefixCalculate(path, pl1) assert.Equal(t, false, match1) pl2, _ := NewPrefix(net.ParseIP("2001:123:123:1::"), 64, "") - match2 := IpPrefixCalculate(path, pl2) + match2 := ipPrefixCalculate(path, pl2) assert.Equal(t, true, match2) pl3, _ := NewPrefix(net.ParseIP("2001:123:123::"), 48, "64..80") - match3 := IpPrefixCalculate(path, pl3) + match3 := ipPrefixCalculate(path, pl3) assert.Equal(t, true, match3) } @@ -163,10 +163,10 @@ func TestPrefixCalcurateAddressIPv6(t *testing.T) { path := table.ProcessMessage(updateMsg, peer)[0] // test pl1, _ := NewPrefix(net.ParseIP("2001:123:128::"), 48, "64..80") - match1 := IpPrefixCalculate(path, pl1) + match1 := ipPrefixCalculate(path, pl1) assert.Equal(t, false, match1) pl2, _ := NewPrefix(net.ParseIP("2001:123:123::"), 48, "64..80") - match2 := IpPrefixCalculate(path, pl2) + match2 := ipPrefixCalculate(path, pl2) assert.Equal(t, true, match2) } @@ -186,10 +186,10 @@ func TestPrefixCalcurateLengthIPv6(t *testing.T) { path := table.ProcessMessage(updateMsg, peer)[0] // test pl1, _ := NewPrefix(net.ParseIP("2001:123:123:64::"), 64, "64..80") - match1 := IpPrefixCalculate(path, pl1) + match1 := ipPrefixCalculate(path, pl1) assert.Equal(t, false, match1) pl2, _ := NewPrefix(net.ParseIP("2001:123:123:64::"), 48, "64..80") - match2 := IpPrefixCalculate(path, pl2) + match2 := ipPrefixCalculate(path, pl2) assert.Equal(t, true, match2) } @@ -209,13 +209,13 @@ func TestPrefixCalcurateLengthRangeIPv6(t *testing.T) { path := table.ProcessMessage(updateMsg, peer)[0] // test pl1, _ := NewPrefix(net.ParseIP("2001:123:123::"), 48, "62..63") - match1 := IpPrefixCalculate(path, pl1) + match1 := ipPrefixCalculate(path, pl1) assert.Equal(t, false, match1) pl2, _ := NewPrefix(net.ParseIP("2001:123:123::"), 48, "65..66") - match2 := IpPrefixCalculate(path, pl2) + match2 := ipPrefixCalculate(path, pl2) assert.Equal(t, false, match2) pl3, _ := NewPrefix(net.ParseIP("2001:123:123::"), 48, "63..65") - match3 := IpPrefixCalculate(path, pl3) + match3 := ipPrefixCalculate(path, pl3) assert.Equal(t, true, match3) } @@ -632,3 +632,133 @@ func TestPolicyDifferentRoutefamilyOfPathAndPolicy(t *testing.T) { assert.Equal(t, ROUTE_TYPE_REJECT, pType2) assert.Equal(t, nil, newPath2) } + +func TestAsPathLengthConditionEvaluate(t *testing.T) { + // setup + // create path + peer := &table.PeerInfo{AS: 65001, Address: net.ParseIP("10.0.0.1")} + origin := bgp.NewPathAttributeOrigin(0) + aspathParam := []bgp.AsPathParamInterface{ + bgp.NewAsPathParam(2, []uint16{65001, 65000, 65004, 65005}), + bgp.NewAsPathParam(1, []uint16{65001, 65000, 65004, 65005}), + } + aspath := bgp.NewPathAttributeAsPath(aspathParam) + nexthop := bgp.NewPathAttributeNextHop("10.0.0.1") + med := bgp.NewPathAttributeMultiExitDisc(0) + pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med} + nlri := []bgp.NLRInfo{*bgp.NewNLRInfo(24, "10.10.0.101")} + withdrawnRoutes := []bgp.WithdrawnRoute{} + updateMsg := bgp.NewBGPUpdateMessage(withdrawnRoutes, pathAttributes, nlri) + table.UpdatePathAttrs4ByteAs(updateMsg.Body.(*bgp.BGPUpdate)) + msg := table.NewProcessMessage(updateMsg, peer) + path := msg.ToPathList()[0] + + // create match condition + asPathLength := config.AsPathLength{ + Operator: "eq", + Value: 8, + } + c := NewAsPathLengthCondition(asPathLength) + + // test + assert.Equal(t, true, c.evaluate(path)) + + // create match condition + asPathLength = config.AsPathLength{ + Operator: "ge", + Value: 3, + } + c = NewAsPathLengthCondition(asPathLength) + + // test + assert.Equal(t, true, c.evaluate(path)) + + // create match condition + asPathLength = config.AsPathLength{ + Operator: "le", + Value: 3, + } + c = NewAsPathLengthCondition(asPathLength) + + // test + assert.Equal(t, false, c.evaluate(path)) +} + +func TestAsPathLengthConditionWithOtherCondition(t *testing.T) { + // setup + // create path + peer := &table.PeerInfo{AS: 65001, Address: net.ParseIP("10.0.0.1")} + origin := bgp.NewPathAttributeOrigin(0) + aspathParam := []bgp.AsPathParamInterface{ + bgp.NewAsPathParam(2, []uint16{65001, 65000, 65004, 65004, 65005}), + bgp.NewAsPathParam(1, []uint16{65001, 65000, 65004, 65005}), + } + aspath := bgp.NewPathAttributeAsPath(aspathParam) + nexthop := bgp.NewPathAttributeNextHop("10.0.0.1") + med := bgp.NewPathAttributeMultiExitDisc(0) + pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med} + nlri := []bgp.NLRInfo{*bgp.NewNLRInfo(24, "10.10.0.101")} + withdrawnRoutes := []bgp.WithdrawnRoute{} + updateMsg := bgp.NewBGPUpdateMessage(withdrawnRoutes, pathAttributes, nlri) + table.UpdatePathAttrs4ByteAs(updateMsg.Body.(*bgp.BGPUpdate)) + msg := table.NewProcessMessage(updateMsg, peer) + path := msg.ToPathList()[0] + + // create policy + ps := config.PrefixSet{ + PrefixSetName: "ps1", + PrefixList: []config.Prefix{ + config.Prefix{ + Address: net.ParseIP("10.10.1.0"), + Masklength: 16, + MasklengthRange: "21..24", + }}, + } + ns := config.NeighborSet{ + NeighborSetName: "ns1", + NeighborInfoList: []config.NeighborInfo{ + config.NeighborInfo{ + Address: net.ParseIP("10.0.1.1"), + }}, + } + + ds := config.DefinedSets{ + PrefixSetList: []config.PrefixSet{ps}, + NeighborSetList: []config.NeighborSet{ns}, + } + + // create match condition + asPathLength := config.AsPathLength{ + Operator: "le", + Value: 10, + } + + bgpCondition := config.BgpConditions{ + AsPathLength: asPathLength, + } + + s := config.Statement{ + Name: "statement1", + Conditions: config.Conditions{ + MatchPrefixSet: "ps1", + MatchNeighborSet: "ns1", + MatchSetOptions: config.MATCH_SET_OPTIONS_TYPE_ANY, + BgpConditions: bgpCondition, + }, + Actions: config.Actions{ + RejectRoute: true, + }, + } + pd := config.PolicyDefinition{"pd1", []config.Statement{s}} + pl := config.RoutingPolicy{ds, []config.PolicyDefinition{pd}} + + //test + pName := "pd1" + df := pl.DefinedSets + p := NewPolicy(pName, pl.PolicyDefinitionList[0], df) + match, pType, newPath := p.Apply(path) + assert.Equal(t, true, match) + assert.Equal(t, ROUTE_TYPE_REJECT, pType) + assert.Equal(t, nil, newPath) + +} diff --git a/table/path.go b/table/path.go index 29d8a92d..a1f87391 100644 --- a/table/path.go +++ b/table/path.go @@ -33,6 +33,7 @@ type Path interface { getPathAttr(bgp.BGPAttrType) (int, bgp.PathAttributeInterface) updatePathAttrs(global *config.Global, peer *config.Neighbor) GetRouteFamily() bgp.RouteFamily + GetAsPathLen() int setSource(source *PeerInfo) GetSource() *PeerInfo GetSourceAs() uint32 @@ -332,6 +333,34 @@ func (pi *PathDefault) getPrefix() string { return pi.nlri.String() } +// return total length of AS_PATH whose type is AS_SEQ or AS_SET +func (pd *PathDefault) GetAsPathLen() int { + + aslen := func(p *bgp.As4PathParam) int { + if p.Type == bgp.BGP_ASPATH_ATTR_TYPE_SEQ || p.Type == bgp.BGP_ASPATH_ATTR_TYPE_SET { + return p.ASLen() + } + return 0 + } + + var length int = 0 + if _, attr := pd.getPathAttr(bgp.BGP_ATTR_TYPE_AS_PATH); attr != nil { + aspath := attr.(*bgp.PathAttributeAsPath) + for _, paramIf := range aspath.Value { + segment := paramIf.(*bgp.As4PathParam) + length += aslen(segment) + } + + } else { + _, attr := pd.getPathAttr(bgp.BGP_ATTR_TYPE_AS4_PATH) + aspath := attr.(*bgp.PathAttributeAs4Path) + for _, segment := range aspath.Value { + length += aslen(segment) + } + } + return length +} + // create Path object based on route family func CreatePath(source *PeerInfo, nlri bgp.AddrPrefixInterface, attrs []bgp.PathAttributeInterface, isWithdraw bool, now time.Time) (Path, error) { |