diff options
Diffstat (limited to 'table')
-rw-r--r-- | table/adj.go | 16 | ||||
-rw-r--r-- | table/destination.go | 98 | ||||
-rw-r--r-- | table/destination_test.go | 43 | ||||
-rw-r--r-- | table/message.go | 3 | ||||
-rw-r--r-- | table/path.go | 40 | ||||
-rw-r--r-- | table/policy.go | 152 | ||||
-rw-r--r-- | table/policy_test.go | 86 | ||||
-rw-r--r-- | table/table.go | 45 | ||||
-rw-r--r-- | table/table_manager.go | 261 | ||||
-rw-r--r-- | table/table_manager_test.go | 12 |
10 files changed, 389 insertions, 367 deletions
diff --git a/table/adj.go b/table/adj.go index 019ad3c8..d7a0555d 100644 --- a/table/adj.go +++ b/table/adj.go @@ -21,16 +21,18 @@ import ( ) type AdjRib struct { + id string accepted map[bgp.RouteFamily]int table map[bgp.RouteFamily]map[string]*Path } -func NewAdjRib(rfList []bgp.RouteFamily) *AdjRib { +func NewAdjRib(id string, rfList []bgp.RouteFamily) *AdjRib { table := make(map[bgp.RouteFamily]map[string]*Path) for _, rf := range rfList { table[rf] = make(map[string]*Path) } return &AdjRib{ + id: id, table: table, accepted: make(map[bgp.RouteFamily]int), } @@ -47,19 +49,21 @@ func (adj *AdjRib) Update(pathList []*Path) { if path.IsWithdraw { if found { delete(adj.table[rf], key) - if !old.Filtered { + if old.Filtered(adj.id) > POLICY_DIRECTION_NONE { adj.accepted[rf]-- } } } else { + n := path.Filtered(adj.id) if found { - if old.Filtered && !path.Filtered { + o := old.Filtered(adj.id) + if o == POLICY_DIRECTION_IN && n == POLICY_DIRECTION_NONE { adj.accepted[rf]++ - } else if !old.Filtered && path.Filtered { + } else if o == POLICY_DIRECTION_NONE && n == POLICY_DIRECTION_IN { adj.accepted[rf]-- } } else { - if !path.Filtered { + if n == POLICY_DIRECTION_NONE { adj.accepted[rf]++ } } @@ -75,7 +79,7 @@ func (adj *AdjRib) PathList(rfList []bgp.RouteFamily, accepted bool) []*Path { pathList := make([]*Path, 0, adj.Count(rfList)) for _, rf := range rfList { for _, rr := range adj.table[rf] { - if accepted && rr.Filtered { + if accepted && rr.Filtered(adj.id) > POLICY_DIRECTION_NONE { continue } pathList = append(pathList, rr) diff --git a/table/destination.go b/table/destination.go index 7485c987..f83e92e6 100644 --- a/table/destination.go +++ b/table/destination.go @@ -18,7 +18,6 @@ package table import ( "bytes" "encoding/binary" - "encoding/json" "fmt" log "github.com/Sirupsen/logrus" api "github.com/osrg/gobgp/api" @@ -112,14 +111,13 @@ func NewPeerInfo(g *config.Global, p *config.Neighbor) *PeerInfo { } type Destination struct { - routeFamily bgp.RouteFamily - nlri bgp.AddrPrefixInterface - knownPathList paths - withdrawList paths - newPathList paths - bestPath *Path - bestPathReason BestPathReason - RadixKey string + routeFamily bgp.RouteFamily + nlri bgp.AddrPrefixInterface + oldKnownPathList paths + knownPathList paths + withdrawList paths + newPathList paths + RadixKey string } func NewDestination(nlri bgp.AddrPrefixInterface) *Destination { @@ -137,24 +135,27 @@ func NewDestination(nlri bgp.AddrPrefixInterface) *Destination { return d } -func (dd *Destination) MarshalJSON() ([]byte, error) { - return json.Marshal(dd.ToApiStruct()) -} - -func (dd *Destination) ToApiStruct() *api.Destination { +func (dd *Destination) ToApiStruct(id string) *api.Destination { prefix := dd.GetNlri().String() paths := func(arg []*Path) []*api.Path { ret := make([]*api.Path, 0, len(arg)) + first := true for _, p := range arg { - pp := p.ToApiStruct() - if dd.GetBestPath() == p { - pp.Best = true + if p.filtered[id] == POLICY_DIRECTION_NONE { + pp := p.ToApiStruct(id) + if first { + pp.Best = true + first = false + } + ret = append(ret, pp) } - ret = append(ret, pp) } return ret }(dd.knownPathList) + if len(paths) == 0 { + return nil + } return &api.Destination{ Prefix: prefix, Paths: paths, @@ -177,28 +178,32 @@ func (dd *Destination) setNlri(nlri bgp.AddrPrefixInterface) { dd.nlri = nlri } -func (dd *Destination) getBestPathReason() BestPathReason { - return dd.bestPathReason -} - -func (dd *Destination) setBestPathReason(reason BestPathReason) { - dd.bestPathReason = reason -} - -func (dd *Destination) GetBestPath() *Path { - return dd.bestPath -} - -func (dd *Destination) setBestPath(path *Path) { - dd.bestPath = path +func (dd *Destination) GetKnownPathList(id string) []*Path { + list := make([]*Path, 0, len(dd.knownPathList)) + for _, p := range dd.knownPathList { + if p.filtered[id] == POLICY_DIRECTION_NONE { + list = append(list, p) + } + } + return list } -func (dd *Destination) GetKnownPathList() []*Path { - return dd.knownPathList +func (dd *Destination) GetBestPath(id string) *Path { + for _, p := range dd.knownPathList { + if p.filtered[id] == POLICY_DIRECTION_NONE { + return p + } + } + return nil } -func (dd *Destination) setKnownPathList(List []*Path) { - dd.knownPathList = List +func (dd *Destination) oldBest(id string) *Path { + for _, p := range dd.oldKnownPathList { + if p.filtered[id] == POLICY_DIRECTION_NONE { + return p + } + } + return nil } func (dd *Destination) addWithdraw(withdraw *Path) { @@ -229,8 +234,8 @@ func (dd *Destination) validatePath(path *Path) { // // Modifies destination's state related to stored paths. Removes withdrawn // paths from known paths. Also, adds new paths to known paths. -func (dest *Destination) Calculate() (*Path, BestPathReason, error) { - +func (dest *Destination) Calculate() { + dest.oldKnownPathList = dest.knownPathList // First remove the withdrawn paths. dest.explicitWithdraw() // Do implicit withdrawal @@ -240,7 +245,22 @@ func (dest *Destination) Calculate() (*Path, BestPathReason, error) { // Clear new paths as we copied them. dest.newPathList = make([]*Path, 0) // Compute new best path - return dest.computeKnownBestPath() + dest.computeKnownBestPath() +} + +func (dest *Destination) NewFeed(id string) *Path { + old := dest.oldBest(id) + best := dest.GetBestPath(id) + if best != nil && best.Equal(old) { + return nil + } + if best == nil { + if old == nil { + return nil + } + return old.Clone(old.Owner, true) + } + return best } // Removes withdrawn paths. diff --git a/table/destination_test.go b/table/destination_test.go index dce14250..105d7104 100644 --- a/table/destination_test.go +++ b/table/destination_test.go @@ -63,49 +63,6 @@ func TestDestinationGetNlri(t *testing.T) { r_nlri := dd.GetNlri() assert.Equal(t, r_nlri, nlri) } -func TestDestinationSetBestPathReason(t *testing.T) { - dd := &Destination{} - reason := BestPathReason("reason1") - dd.setBestPathReason(reason) - r_reason := dd.getBestPathReason() - assert.Equal(t, r_reason, reason) -} -func TestDestinationGetBestPathReason(t *testing.T) { - dd := &Destination{} - reason := BestPathReason("reason2") - dd.setBestPathReason(reason) - r_reason := dd.getBestPathReason() - assert.Equal(t, r_reason, reason) -} -func TestDestinationSetBestPath(t *testing.T) { - peerD := DestCreatePeer() - pathD := DestCreatePath(peerD) - ipv4d := NewDestination(pathD[0].GetNlri()) - ipv4d.setBestPath(pathD[0]) - r_pathD := ipv4d.GetBestPath() - assert.Equal(t, r_pathD, pathD[0]) -} -func TestDestinationGetBestPath(t *testing.T) { - peerD := DestCreatePeer() - pathD := DestCreatePath(peerD) - ipv4d := NewDestination(pathD[0].GetNlri()) - ipv4d.setBestPath(pathD[0]) - r_pathD := ipv4d.GetBestPath() - assert.Equal(t, r_pathD, pathD[0]) -} -func TestDestinationCalculate(t *testing.T) { - peerD := DestCreatePeer() - pathD := DestCreatePath(peerD) - ipv4d := NewDestination(pathD[0].GetNlri()) - //best path selection - ipv4d.addNewPath(pathD[0]) - ipv4d.addNewPath(pathD[1]) - ipv4d.addNewPath(pathD[2]) - ipv4d.addWithdraw(pathD[2]) - _, _, e := ipv4d.Calculate() - assert.Nil(t, e) -} - func DestCreatePeer() []*PeerInfo { peerD1 := &PeerInfo{AS: 65000} peerD2 := &PeerInfo{AS: 65001} diff --git a/table/message.go b/table/message.go index 3ec0ef62..c6437d18 100644 --- a/table/message.go +++ b/table/message.go @@ -194,6 +194,9 @@ func CreateUpdateMsgFromPaths(pathList []*Path) []*bgp.BGPMessage { pathByAttrs := make(map[uint32][]*bucket) pathLen := len(pathList) for _, path := range pathList { + if path == nil { + continue + } y := func(p *Path) bool { // the merging logic makes gobgpd slower so if // paths are not many, let's avoid mering. diff --git a/table/path.go b/table/path.go index 7cfe37b0..73b02061 100644 --- a/table/path.go +++ b/table/path.go @@ -38,9 +38,10 @@ type Path struct { NoImplicitWithdraw bool Validation config.RpkiValidationResultType IsFromZebra bool - Filtered bool Owner net.IP reason BestPathReason + filtered map[string]PolicyDirection + key string } func NewPath(source *PeerInfo, nlri bgp.AddrPrefixInterface, isWithdraw bool, pattrs []bgp.PathAttributeInterface, medSetByTargetNeighbor bool, timestamp time.Time, noImplicitWithdraw bool) *Path { @@ -67,6 +68,7 @@ func NewPath(source *PeerInfo, nlri bgp.AddrPrefixInterface, isWithdraw bool, pa timestamp: timestamp, NoImplicitWithdraw: noImplicitWithdraw, Owner: owner, + filtered: make(map[string]PolicyDirection), } } @@ -188,7 +190,7 @@ func (path *Path) IsIBGP() bool { return path.source.AS == path.source.LocalAS } -func (path *Path) ToApiStruct() *api.Path { +func (path *Path) ToApiStruct(id string) *api.Path { nlri := path.GetNlri() n, _ := nlri.Serialize() rf := uint32(bgp.AfiSafiToRouteFamily(nlri.AFI(), nlri.SAFI())) @@ -206,27 +208,11 @@ func (path *Path) ToApiStruct() *api.Path { Age: int64(time.Now().Sub(path.timestamp).Seconds()), IsWithdraw: path.IsWithdraw, Validation: int32(path.Validation), - Filtered: path.Filtered, + Filtered: path.Filtered(id) > POLICY_DIRECTION_NONE, Rf: rf, } } -func (path *Path) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Source *PeerInfo `json:"source"` - IsWithdraw bool `json:"is_withdraw"` - Nlri bgp.AddrPrefixInterface `json:"nlri"` - Pathattrs []bgp.PathAttributeInterface `json:"pattrs"` - Filtered bool `json:"filtered"` - }{ - Source: path.source, - IsWithdraw: path.IsWithdraw, - Nlri: path.nlri, - Pathattrs: path.pathAttrs, - Filtered: path.Filtered, - }) -} - // create new PathAttributes func (path *Path) Clone(owner net.IP, isWithdraw bool) *Path { newPathAttrs := make([]bgp.PathAttributeInterface, len(path.pathAttrs)) @@ -237,9 +223,18 @@ func (path *Path) Clone(owner net.IP, isWithdraw bool) *Path { p := NewPath(path.source, path.nlri, isWithdraw, newPathAttrs, false, path.timestamp, path.NoImplicitWithdraw) p.Validation = path.Validation p.Owner = owner + p.key = path.key return p } +func (path *Path) Filter(id string, reason PolicyDirection) { + path.filtered[id] = reason +} + +func (path *Path) Filtered(id string) PolicyDirection { + return path.filtered[id] +} + func (path *Path) GetRouteFamily() bgp.RouteFamily { return bgp.AfiSafiToRouteFamily(path.nlri.AFI(), path.nlri.SAFI()) } @@ -332,7 +327,10 @@ func (path *Path) String() string { } func (path *Path) getPrefix() string { - return path.nlri.String() + if path.key == "" { + return path.nlri.String() + } + return path.key } func (path *Path) GetAsPath() *bgp.PathAttributeAsPath { @@ -655,7 +653,7 @@ func (lhs *Path) Equal(rhs *Path) bool { return true } f := func(p *Path) []byte { - s := p.ToApiStruct() + s := p.ToApiStruct(GLOBAL_RIB_NAME) s.Age = 0 buf, _ := json.Marshal(s) return buf diff --git a/table/policy.go b/table/policy.go index b3799e35..6e5a94b2 100644 --- a/table/policy.go +++ b/table/policy.go @@ -64,11 +64,23 @@ type PolicyDirection int const ( POLICY_DIRECTION_NONE PolicyDirection = iota + POLICY_DIRECTION_IN POLICY_DIRECTION_IMPORT POLICY_DIRECTION_EXPORT - POLICY_DIRECTION_IN ) +func (d PolicyDirection) String() string { + switch d { + case POLICY_DIRECTION_IN: + return "in" + case POLICY_DIRECTION_IMPORT: + return "import" + case POLICY_DIRECTION_EXPORT: + return "export" + } + return fmt.Sprintf("unknown(%d)", d) +} + type MatchOption int const ( @@ -2597,10 +2609,115 @@ func NewPolicy(c config.PolicyDefinition, dmap DefinedSetMap) (*Policy, error) { }, nil } +type Assignment struct { + inPolicies []*Policy + defaultInPolicy RouteType + importPolicies []*Policy + defaultImportPolicy RouteType + exportPolicies []*Policy + defaultExportPolicy RouteType +} + type RoutingPolicy struct { DefinedSetMap DefinedSetMap PolicyMap map[string]*Policy StatementMap map[string]*Statement + AssignmentMap map[string]*Assignment +} + +func (r *RoutingPolicy) ApplyPolicy(id string, dir PolicyDirection, before *Path) *Path { + if before == nil { + return nil + } + if filtered := before.Filtered(id); filtered > POLICY_DIRECTION_NONE && filtered < dir { + return nil + } + result := ROUTE_TYPE_NONE + after := before + for _, p := range r.GetPolicy(id, dir) { + result, after = p.Apply(before) + if result != ROUTE_TYPE_NONE { + break + } + } + if result == ROUTE_TYPE_NONE { + result = r.GetDefaultPolicy(id, dir) + } + switch result { + case ROUTE_TYPE_ACCEPT: + return after + default: + return nil + } +} + +func (r *RoutingPolicy) GetPolicy(id string, dir PolicyDirection) []*Policy { + a, ok := r.AssignmentMap[id] + if !ok { + return nil + } + switch dir { + case POLICY_DIRECTION_IN: + return a.inPolicies + case POLICY_DIRECTION_IMPORT: + return a.importPolicies + case POLICY_DIRECTION_EXPORT: + return a.exportPolicies + default: + return nil + } +} + +func (r *RoutingPolicy) GetDefaultPolicy(id string, dir PolicyDirection) RouteType { + a, ok := r.AssignmentMap[id] + if !ok { + return ROUTE_TYPE_NONE + } + switch dir { + case POLICY_DIRECTION_IN: + return a.defaultInPolicy + case POLICY_DIRECTION_IMPORT: + return a.defaultImportPolicy + case POLICY_DIRECTION_EXPORT: + return a.defaultExportPolicy + default: + return ROUTE_TYPE_NONE + } + +} + +func (r *RoutingPolicy) SetPolicy(id string, dir PolicyDirection, policies []*Policy) error { + a, ok := r.AssignmentMap[id] + if !ok { + a = &Assignment{} + } + switch dir { + case POLICY_DIRECTION_IN: + a.inPolicies = policies + case POLICY_DIRECTION_IMPORT: + a.importPolicies = policies + case POLICY_DIRECTION_EXPORT: + a.exportPolicies = policies + } + r.AssignmentMap[id] = a + return nil +} + +func (r *RoutingPolicy) SetDefaultPolicy(id string, dir PolicyDirection, typ RouteType) error { + a, ok := r.AssignmentMap[id] + if !ok { + a = &Assignment{} + } + switch dir { + case POLICY_DIRECTION_IN: + a.defaultInPolicy = typ + case POLICY_DIRECTION_IMPORT: + a.defaultImportPolicy = typ + case POLICY_DIRECTION_EXPORT: + a.defaultExportPolicy = typ + } + r.AssignmentMap[id] = a + return nil } func (r *RoutingPolicy) GetAssignmentFromConfig(dir PolicyDirection, a config.ApplyPolicy) ([]*Policy, RouteType, error) { @@ -2660,14 +2777,14 @@ func (r *RoutingPolicy) StatementInUse(x *Statement) bool { return false } -func NewRoutingPolicy(c config.RoutingPolicy) (*RoutingPolicy, error) { +func (r *RoutingPolicy) Reload(c config.RoutingPolicy) error { dmap := make(map[DefinedType]map[string]DefinedSet) dmap[DEFINED_TYPE_PREFIX] = make(map[string]DefinedSet) d := c.DefinedSets for _, x := range d.PrefixSets.PrefixSetList { y, err := NewPrefixSet(x) if err != nil { - return nil, err + return err } dmap[DEFINED_TYPE_PREFIX][y.Name()] = y } @@ -2675,7 +2792,7 @@ func NewRoutingPolicy(c config.RoutingPolicy) (*RoutingPolicy, error) { for _, x := range d.NeighborSets.NeighborSetList { y, err := NewNeighborSet(x) if err != nil { - return nil, err + return err } dmap[DEFINED_TYPE_NEIGHBOR][y.Name()] = y } @@ -2692,7 +2809,7 @@ func NewRoutingPolicy(c config.RoutingPolicy) (*RoutingPolicy, error) { for _, x := range bd.AsPathSets.AsPathSetList { y, err := NewAsPathSet(x) if err != nil { - return nil, err + return err } dmap[DEFINED_TYPE_AS_PATH][y.Name()] = y } @@ -2700,7 +2817,7 @@ func NewRoutingPolicy(c config.RoutingPolicy) (*RoutingPolicy, error) { for _, x := range bd.CommunitySets.CommunitySetList { y, err := NewCommunitySet(x) if err != nil { - return nil, err + return err } dmap[DEFINED_TYPE_COMMUNITY][y.Name()] = y } @@ -2708,7 +2825,7 @@ func NewRoutingPolicy(c config.RoutingPolicy) (*RoutingPolicy, error) { for _, x := range bd.ExtCommunitySets.ExtCommunitySetList { y, err := NewExtCommunitySet(x) if err != nil { - return nil, err + return err } dmap[DEFINED_TYPE_EXT_COMMUNITY][y.Name()] = y } @@ -2717,22 +2834,31 @@ func NewRoutingPolicy(c config.RoutingPolicy) (*RoutingPolicy, error) { for _, x := range c.PolicyDefinitions.PolicyDefinitionList { y, err := NewPolicy(x, dmap) if err != nil { - return nil, err + return err } pmap[y.Name()] = y for _, s := range y.Statements { _, ok := smap[s.Name] if ok { - return nil, fmt.Errorf("duplicated statement name. statement name must be unique.") + return fmt.Errorf("duplicated statement name. statement name must be unique.") } smap[s.Name] = s } } + r.DefinedSetMap = dmap + r.PolicyMap = pmap + r.StatementMap = smap + r.AssignmentMap = make(map[string]*Assignment) + return nil +} + +func NewRoutingPolicy() *RoutingPolicy { return &RoutingPolicy{ - DefinedSetMap: dmap, - PolicyMap: pmap, - StatementMap: smap, - }, nil + DefinedSetMap: make(map[DefinedType]map[string]DefinedSet), + PolicyMap: make(map[string]*Policy), + StatementMap: make(map[string]*Statement), + AssignmentMap: make(map[string]*Assignment), + } } func CanImportToVrf(v *Vrf, path *Path) bool { diff --git a/table/policy_test.go b/table/policy_test.go index 92f6142b..c29b15c1 100644 --- a/table/policy_test.go +++ b/table/policy_test.go @@ -238,7 +238,8 @@ func TestPolicyNotMatch(t *testing.T) { pd := createPolicyDefinition("pd1", s) pl := createRoutingPolicy(ds, pd) - r, err := NewRoutingPolicy(pl) + r := NewRoutingPolicy() + err := r.Reload(pl) assert.Nil(t, err) pType, newPath := r.PolicyMap["pd1"].Apply(path) assert.Equal(t, ROUTE_TYPE_NONE, pType) @@ -268,7 +269,8 @@ func TestPolicyMatchAndReject(t *testing.T) { pd := createPolicyDefinition("pd1", s) pl := createRoutingPolicy(ds, pd) - r, err := NewRoutingPolicy(pl) + r := NewRoutingPolicy() + err := r.Reload(pl) assert.Nil(t, err) pType, newPath := r.PolicyMap["pd1"].Apply(path) assert.Equal(t, ROUTE_TYPE_REJECT, pType) @@ -299,7 +301,8 @@ func TestPolicyMatchAndAccept(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - r, err := NewRoutingPolicy(pl) + r := NewRoutingPolicy() + err := r.Reload(pl) assert.Nil(t, err) pType, newPath := r.PolicyMap["pd1"].Apply(path) assert.Equal(t, ROUTE_TYPE_ACCEPT, pType) @@ -340,7 +343,8 @@ func TestPolicyRejectOnlyPrefixSet(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - r, err := NewRoutingPolicy(pl) + r := NewRoutingPolicy() + err := r.Reload(pl) assert.Nil(t, err) p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path1) @@ -386,7 +390,8 @@ func TestPolicyRejectOnlyNeighborSet(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - r, err := NewRoutingPolicy(pl) + r := NewRoutingPolicy() + err := r.Reload(pl) assert.Nil(t, err) pType, newPath := r.PolicyMap["pd1"].Apply(path1) assert.Equal(t, ROUTE_TYPE_REJECT, pType) @@ -438,7 +443,8 @@ func TestPolicyDifferentRoutefamilyOfPathAndPolicy(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - r, err := NewRoutingPolicy(pl) + r := NewRoutingPolicy() + err := r.Reload(pl) assert.Nil(t, err) p := r.PolicyMap["pd1"] pType1, newPath1 := p.Apply(pathIPv4) @@ -537,7 +543,8 @@ func TestAsPathLengthConditionWithOtherCondition(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - r, err := NewRoutingPolicy(pl) + r := NewRoutingPolicy() + err := r.Reload(pl) assert.Nil(t, err) p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) @@ -654,7 +661,8 @@ func TestAs4PathLengthConditionWithOtherCondition(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - r, _ := NewRoutingPolicy(pl) + r := NewRoutingPolicy() + r.Reload(pl) p, _ := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], r.DefinedSetMap) pType, newPath := p.Apply(path) assert.Equal(t, ROUTE_TYPE_REJECT, pType) @@ -997,7 +1005,8 @@ func TestAsPathConditionWithOtherCondition(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - r, err := NewRoutingPolicy(pl) + r := NewRoutingPolicy() + err := r.Reload(pl) assert.Nil(t, err) p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) @@ -1302,7 +1311,8 @@ func TestAs4PathConditionWithOtherCondition(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - r, _ := NewRoutingPolicy(pl) + r := NewRoutingPolicy() + r.Reload(pl) p, _ := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], r.DefinedSetMap) pType, newPath := p.Apply(path) assert.Equal(t, ROUTE_TYPE_REJECT, pType) @@ -1661,7 +1671,8 @@ func TestCommunityConditionEvaluateWithOtherCondition(t *testing.T) { pl := createRoutingPolicy(ds, pd1, pd2) //test - r, err := NewRoutingPolicy(pl) + r := NewRoutingPolicy() + err := r.Reload(pl) assert.Nil(t, err) p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) @@ -1705,7 +1716,8 @@ func TestPolicyMatchAndAddCommunities(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - r, err := NewRoutingPolicy(pl) + r := NewRoutingPolicy() + err := r.Reload(pl) assert.Nil(t, err) p := r.PolicyMap["pd1"] @@ -1749,7 +1761,8 @@ func TestPolicyMatchAndReplaceCommunities(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - r, err := NewRoutingPolicy(pl) + r := NewRoutingPolicy() + err := r.Reload(pl) assert.Nil(t, err) p := r.PolicyMap["pd1"] @@ -1793,7 +1806,8 @@ func TestPolicyMatchAndRemoveCommunities(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - r, err := NewRoutingPolicy(pl) + r := NewRoutingPolicy() + err := r.Reload(pl) assert.Nil(t, err) p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) @@ -1838,7 +1852,8 @@ func TestPolicyMatchAndRemoveCommunitiesRegexp(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - r, err := NewRoutingPolicy(pl) + r := NewRoutingPolicy() + err := r.Reload(pl) assert.Nil(t, err) p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) @@ -1883,7 +1898,8 @@ func TestPolicyMatchAndRemoveCommunitiesRegexp2(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - r, err := NewRoutingPolicy(pl) + r := NewRoutingPolicy() + err := r.Reload(pl) assert.Nil(t, err) p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) @@ -1928,7 +1944,8 @@ func TestPolicyMatchAndClearCommunities(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - r, err := NewRoutingPolicy(pl) + r := NewRoutingPolicy() + err := r.Reload(pl) assert.Nil(t, err) p := r.PolicyMap["pd1"] @@ -2262,7 +2279,8 @@ func TestExtCommunityConditionEvaluateWithOtherCondition(t *testing.T) { pd2 := createPolicyDefinition("pd2", s2) pl := createRoutingPolicy(ds, pd1, pd2) //test - r, err := NewRoutingPolicy(pl) + r := NewRoutingPolicy() + err := r.Reload(pl) assert.Nil(t, err) p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) @@ -2306,7 +2324,8 @@ func TestPolicyMatchAndReplaceMed(t *testing.T) { pl := createRoutingPolicy(ds, pd) //test - r, err := NewRoutingPolicy(pl) + r := NewRoutingPolicy() + err := r.Reload(pl) assert.Nil(t, err) p := r.PolicyMap["pd1"] @@ -2349,7 +2368,8 @@ func TestPolicyMatchAndAddingMed(t *testing.T) { pd := createPolicyDefinition("pd1", s) pl := createRoutingPolicy(ds, pd) //test - r, err := NewRoutingPolicy(pl) + r := NewRoutingPolicy() + err := r.Reload(pl) assert.Nil(t, err) p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) @@ -2393,7 +2413,8 @@ func TestPolicyMatchAndAddingMedOverFlow(t *testing.T) { pd := createPolicyDefinition("pd1", s) pl := createRoutingPolicy(ds, pd) //test - r, err := NewRoutingPolicy(pl) + r := NewRoutingPolicy() + err := r.Reload(pl) assert.Nil(t, err) p := r.PolicyMap["pd1"] @@ -2438,7 +2459,8 @@ func TestPolicyMatchAndSubtractMed(t *testing.T) { pd := createPolicyDefinition("pd1", s) pl := createRoutingPolicy(ds, pd) //test - r, err := NewRoutingPolicy(pl) + r := NewRoutingPolicy() + err := r.Reload(pl) assert.Nil(t, err) p := r.PolicyMap["pd1"] @@ -2483,7 +2505,8 @@ func TestPolicyMatchAndSubtractMedUnderFlow(t *testing.T) { pd := createPolicyDefinition("pd1", s) pl := createRoutingPolicy(ds, pd) //test - r, err := NewRoutingPolicy(pl) + r := NewRoutingPolicy() + err := r.Reload(pl) assert.Nil(t, err) p := r.PolicyMap["pd1"] @@ -2525,7 +2548,8 @@ func TestPolicyMatchWhenPathHaveNotMed(t *testing.T) { pd := createPolicyDefinition("pd1", s) pl := createRoutingPolicy(ds, pd) //test - r, err := NewRoutingPolicy(pl) + r := NewRoutingPolicy() + err := r.Reload(pl) assert.Nil(t, err) p := r.PolicyMap["pd1"] @@ -2572,8 +2596,8 @@ func TestPolicyAsPathPrepend(t *testing.T) { pd := createPolicyDefinition("pd1", s) pl := createRoutingPolicy(ds, pd) //test - r, _ := NewRoutingPolicy(pl) - // assert.Nil(t, err) + r := NewRoutingPolicy() + r.Reload(pl) p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) @@ -2616,8 +2640,8 @@ func TestPolicyAsPathPrependLastAs(t *testing.T) { pd := createPolicyDefinition("pd1", s) pl := createRoutingPolicy(ds, pd) //test - r, _ := NewRoutingPolicy(pl) - // assert.Nil(t, err) + r := NewRoutingPolicy() + r.Reload(pl) p := r.PolicyMap["pd1"] pType, newPath := p.Apply(path) @@ -2666,7 +2690,8 @@ func TestPolicyAs4PathPrepend(t *testing.T) { pd := createPolicyDefinition("pd1", s) pl := createRoutingPolicy(ds, pd) //test - r, _ := NewRoutingPolicy(pl) + r := NewRoutingPolicy() + r.Reload(pl) p, _ := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], r.DefinedSetMap) pType, newPath := p.Apply(path) @@ -2720,7 +2745,8 @@ func TestPolicyAs4PathPrependLastAs(t *testing.T) { pd := createPolicyDefinition("pd1", s) pl := createRoutingPolicy(ds, pd) //test - r, _ := NewRoutingPolicy(pl) + r := NewRoutingPolicy() + r.Reload(pl) p, _ := NewPolicy(pl.PolicyDefinitions.PolicyDefinitionList[0], r.DefinedSetMap) pType, newPath := p.Apply(path) diff --git a/table/table.go b/table/table.go index cf14d5c1..36a29ed4 100644 --- a/table/table.go +++ b/table/table.go @@ -51,28 +51,28 @@ func (t *Table) insert(path *Path) *Destination { } func (t *Table) DeleteDestByPeer(peerInfo *PeerInfo) []*Destination { - changedDests := make([]*Destination, 0) - for _, dest := range t.destinations { - newKnownPathList := make([]*Path, 0) - for _, p := range dest.GetKnownPathList() { - if !p.GetSource().Equal(peerInfo) { - newKnownPathList = append(newKnownPathList, p) + dsts := []*Destination{} + for _, dst := range t.destinations { + match := false + for _, p := range dst.knownPathList { + if p.GetSource().Equal(peerInfo) { + dst.addWithdraw(p) + match = true } } - if len(newKnownPathList) != len(dest.GetKnownPathList()) { - changedDests = append(changedDests, dest) - dest.setKnownPathList(newKnownPathList) + if match { + dsts = append(dsts, dst) } } - return changedDests + return dsts } func (t *Table) deletePathsByVrf(vrf *Vrf) []*Path { pathList := make([]*Path, 0) for _, dest := range t.destinations { - for _, p := range dest.GetKnownPathList() { + for _, p := range dest.knownPathList { var rd bgp.RouteDistinguisherInterface - nlri := p.GetNlri() + nlri := p.nlri switch nlri.(type) { case *bgp.LabeledVPNIPAddrPrefix: rd = nlri.(*bgp.LabeledVPNIPAddrPrefix).RD @@ -104,7 +104,7 @@ func (t *Table) deleteRTCPathsByVrf(vrf *Vrf, vrfs map[string]*Vrf) []*Path { nlri := dest.GetNlri().(*bgp.RouteTargetMembershipNLRI) rhs := nlri.RouteTarget.String() if lhs == rhs && isLastTargetUser(vrfs, target) { - for _, p := range dest.GetKnownPathList() { + for _, p := range dest.knownPathList { if p.IsLocal() { p.IsWithdraw = true pathList = append(pathList, p) @@ -210,3 +210,22 @@ func (t *Table) setDestination(key string, dest *Destination) { func (t *Table) tableKey(nlri bgp.AddrPrefixInterface) string { return nlri.String() } + +func (t *Table) Bests(id string) []*Path { + paths := make([]*Path, 0, len(t.destinations)) + for _, dst := range t.destinations { + path := dst.GetBestPath(id) + if path != nil { + paths = append(paths, path) + } + } + return paths +} + +func (t *Table) GetKnownPathList(id string) []*Path { + paths := make([]*Path, 0, len(t.destinations)) + for _, dst := range t.destinations { + paths = append(paths, dst.GetKnownPathList(id)...) + } + return paths +} diff --git a/table/table_manager.go b/table/table_manager.go index 637299b9..cc73c89b 100644 --- a/table/table_manager.go +++ b/table/table_manager.go @@ -24,6 +24,10 @@ import ( "time" ) +const ( + GLOBAL_RIB_NAME = "global" +) + func nlri2Path(m *bgp.BGPMessage, p *PeerInfo, now time.Time) []*Path { updateMsg := m.Body.(*bgp.BGPUpdate) pathAttributes := updateMsg.PathAttributes @@ -105,17 +109,13 @@ func ProcessMessage(m *bgp.BGPMessage, peerInfo *PeerInfo, timestamp time.Time) } type TableManager struct { - Tables map[bgp.RouteFamily]*Table - Vrfs map[string]*Vrf - owner string - minLabel uint32 - maxLabel uint32 - nextLabel uint32 - rfList []bgp.RouteFamily - importPolicies []*Policy - defaultImportPolicy RouteType - exportPolicies []*Policy - defaultExportPolicy RouteType + Tables map[bgp.RouteFamily]*Table + Vrfs map[string]*Vrf + owner string + minLabel uint32 + maxLabel uint32 + nextLabel uint32 + rfList []bgp.RouteFamily } func NewTableManager(owner string, rfList []bgp.RouteFamily, minLabel, maxLabel uint32) *TableManager { @@ -138,82 +138,6 @@ func (manager *TableManager) GetRFlist() []bgp.RouteFamily { return manager.rfList } -func (manager *TableManager) GetPolicy(d PolicyDirection) []*Policy { - switch d { - case POLICY_DIRECTION_IMPORT: - return manager.importPolicies - case POLICY_DIRECTION_EXPORT: - return manager.exportPolicies - } - return nil -} - -func (manager *TableManager) SetPolicy(d PolicyDirection, policies []*Policy) error { - switch d { - case POLICY_DIRECTION_IMPORT: - manager.importPolicies = policies - case POLICY_DIRECTION_EXPORT: - manager.exportPolicies = policies - default: - return fmt.Errorf("unsupported policy type: %d", d) - } - return nil -} - -func (manager *TableManager) GetDefaultPolicy(d PolicyDirection) RouteType { - switch d { - case POLICY_DIRECTION_IMPORT: - return manager.defaultImportPolicy - case POLICY_DIRECTION_EXPORT: - return manager.defaultExportPolicy - } - return ROUTE_TYPE_NONE -} - -func (manager *TableManager) SetDefaultPolicy(d PolicyDirection, typ RouteType) error { - switch d { - case POLICY_DIRECTION_IMPORT: - manager.defaultImportPolicy = typ - case POLICY_DIRECTION_EXPORT: - manager.defaultExportPolicy = typ - default: - return fmt.Errorf("unsupported policy type: %d", d) - } - return nil -} - -func (manager *TableManager) ApplyPolicy(d PolicyDirection, paths []*Path) []*Path { - newpaths := make([]*Path, 0, len(paths)) - for _, path := range paths { - result := ROUTE_TYPE_NONE - newpath := path - for _, p := range manager.GetPolicy(d) { - result, newpath = p.Apply(path) - if result != ROUTE_TYPE_NONE { - break - } - } - - if result == ROUTE_TYPE_NONE { - result = manager.GetDefaultPolicy(d) - } - - switch result { - case ROUTE_TYPE_ACCEPT: - newpaths = append(newpaths, newpath) - case ROUTE_TYPE_REJECT: - path.Filtered = true - log.WithFields(log.Fields{ - "Topic": "Peer", - "Key": path.GetSource().Address, - "Path": path, - "Direction": d, - }).Debug("reject") - } - } - return newpaths -} - func (manager *TableManager) GetNextLabel(name, nexthop string, isWithdraw bool) (uint32, error) { var label uint32 var err error @@ -295,122 +219,67 @@ func (manager *TableManager) DeleteVrf(name string) ([]*Path, error) { return msgs, nil } -func (manager *TableManager) calculate(destinationList []*Destination) ([]*Path, error) { - newPaths := make([]*Path, 0) - - for _, destination := range destinationList { - // compute best path - +func (manager *TableManager) calculate(destinations []*Destination) { + for _, destination := range destinations { log.WithFields(log.Fields{ "Topic": "table", "Owner": manager.owner, "Key": destination.GetNlri().String(), }).Debug("Processing destination") + destination.Calculate() + } +} - newBestPath, reason, err := destination.Calculate() - - if err != nil { - log.Error(err) - continue - } - - destination.setBestPathReason(reason) - currentBestPath := destination.GetBestPath() - - if newBestPath != nil && newBestPath.Equal(currentBestPath) { - // best path is not changed - log.WithFields(log.Fields{ - "Topic": "table", - "Owner": manager.owner, - "Key": destination.GetNlri().String(), - "peer": newBestPath.GetSource().Address, - "next_hop": newBestPath.GetNexthop().String(), - "reason": reason, - }).Debug("best path is not changed") - continue - } - - if newBestPath == nil { - log.WithFields(log.Fields{ - "Topic": "table", - "Owner": manager.owner, - "Key": destination.GetNlri().String(), - }).Debug("best path is nil") - - if len(destination.GetKnownPathList()) == 0 { - // create withdraw path - if currentBestPath != nil { - log.WithFields(log.Fields{ - "Topic": "table", - "Owner": manager.owner, - "Key": destination.GetNlri().String(), - "peer": currentBestPath.GetSource().Address, - "next_hop": currentBestPath.GetNexthop().String(), - }).Debug("best path is lost") - - p := destination.GetBestPath() - newPaths = append(newPaths, p.Clone(p.Owner, true)) - } - destination.setBestPath(nil) - } else { - log.WithFields(log.Fields{ - "Topic": "table", - "Owner": manager.owner, - "Key": destination.GetNlri().String(), - }).Error("known path list is not empty") - } - } else { - log.WithFields(log.Fields{ - "Topic": "table", - "Owner": manager.owner, - "Key": newBestPath.GetNlri().String(), - "peer": newBestPath.GetSource().Address, - "next_hop": newBestPath.GetNexthop(), - "reason": reason, - }).Debug("new best path") - - newPaths = append(newPaths, newBestPath) - destination.setBestPath(newBestPath) - } - - if len(destination.GetKnownPathList()) == 0 && destination.GetBestPath() == nil { - rf := destination.getRouteFamily() - t := manager.Tables[rf] - t.deleteDest(destination) - log.WithFields(log.Fields{ - "Topic": "table", - "Owner": manager.owner, - "Key": destination.GetNlri().String(), - "route_family": rf, - }).Debug("destination removed") - } +func (manager *TableManager) DeletePathsByPeer(info *PeerInfo, rf bgp.RouteFamily) []*Destination { + if t, ok := manager.Tables[rf]; ok { + dsts := t.DeleteDestByPeer(info) + manager.calculate(dsts) + return dsts } - return newPaths, nil + return nil } -func (manager *TableManager) DeletePathsforPeer(peerInfo *PeerInfo, rf bgp.RouteFamily) ([]*Path, error) { +func (manager *TableManager) DeletePathsforPeer(id string, peerInfo *PeerInfo, rf bgp.RouteFamily) ([]*Path, error) { if t, ok := manager.Tables[rf]; ok { destinationList := t.DeleteDestByPeer(peerInfo) - return manager.calculate(destinationList) + manager.calculate(destinationList) + paths := make([]*Path, 0, len(destinationList)) + for _, dst := range destinationList { + paths = append(paths, dst.NewFeed(id)) + } + return paths, nil } - return []*Path{}, nil + return nil, nil } -func (manager *TableManager) ProcessPaths(pathList []*Path) ([]*Path, error) { - destinationList := make([]*Destination, 0, len(pathList)) +func (manager *TableManager) ProcessPaths(pathList []*Path) []*Destination { + m := make(map[string]bool, len(pathList)) + dsts := make([]*Destination, 0, len(pathList)) for _, path := range pathList { + if path == nil { + continue + } rf := path.GetRouteFamily() if t, ok := manager.Tables[rf]; ok { - destinationList = append(destinationList, t.insert(path)) + dst := t.insert(path) + key := dst.GetNlri().String() + if !m[key] { + m[key] = true + dsts = append(dsts, dst) + } if rf == bgp.RF_EVPN { - dsts := manager.handleMacMobility(path) - if len(dsts) > 0 { - destinationList = append(destinationList, dsts...) + for _, dst := range manager.handleMacMobility(path) { + key := dst.GetNlri().String() + if !m[key] { + m[key] = true + dsts = append(dsts, dst) + } } } } } - return manager.calculate(destinationList) + manager.calculate(dsts) + return dsts } // EVPN MAC MOBILITY HANDLING @@ -427,7 +296,7 @@ func (manager *TableManager) handleMacMobility(path *Path) []*Destination { if path.IsWithdraw || path.IsLocal() || nlri.RouteType != bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT { return nil } - for _, path2 := range manager.GetPathList(bgp.RF_EVPN) { + for _, path2 := range manager.GetPathList(GLOBAL_RIB_NAME, bgp.RF_EVPN) { if !path2.IsLocal() || path2.GetNlri().(*bgp.EVPNNLRI).RouteType != bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT { continue } @@ -464,27 +333,19 @@ func (manager *TableManager) getDestinationCount(rfList []bgp.RouteFamily) int { return count } -func (manager *TableManager) GetPathList(rf bgp.RouteFamily) []*Path { - if _, ok := manager.Tables[rf]; !ok { - return []*Path{} - } - destinations := manager.Tables[rf].GetDestinations() - paths := make([]*Path, 0, len(destinations)) - for _, dest := range destinations { - paths = append(paths, dest.knownPathList...) - } - return paths -} - -func (manager *TableManager) GetBestPathList(rfList []bgp.RouteFamily) []*Path { +func (manager *TableManager) GetBestPathList(id string, rfList []bgp.RouteFamily) []*Path { paths := make([]*Path, 0, manager.getDestinationCount(rfList)) for _, rf := range rfList { - if _, ok := manager.Tables[rf]; ok { - destinations := manager.Tables[rf].GetDestinations() - for _, dest := range destinations { - paths = append(paths, dest.GetBestPath()) - } + if t, ok := manager.Tables[rf]; ok { + paths = append(paths, t.Bests(id)...) } } return paths } + +func (manager *TableManager) GetPathList(id string, rf bgp.RouteFamily) []*Path { + if t, ok := manager.Tables[rf]; ok { + return t.GetKnownPathList(id) + } + return nil +} diff --git a/table/table_manager_test.go b/table/table_manager_test.go index f0e465b2..e441fb97 100644 --- a/table/table_manager_test.go +++ b/table/table_manager_test.go @@ -30,7 +30,15 @@ import ( // this function processes only BGPUpdate func (manager *TableManager) ProcessUpdate(fromPeer *PeerInfo, message *bgp.BGPMessage) ([]*Path, error) { paths := ProcessMessage(message, fromPeer, time.Now()) - return manager.ProcessPaths(paths) + dsts := manager.ProcessPaths(paths) + paths2 := make([]*Path, 0, len(paths)) + for _, dst := range dsts { + p := dst.NewFeed(GLOBAL_RIB_NAME) + if p != nil { + paths2 = append(paths2, p) + } + } + return paths2, nil } func getLogger(lv log.Level) *log.Logger { @@ -2148,7 +2156,7 @@ func TestProcessBGPUpdate_Timestamp(t *testing.T) { nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.10.0")} - adjRib := NewAdjRib([]bgp.RouteFamily{bgp.RF_IPv4_UC, bgp.RF_IPv6_UC}) + adjRib := NewAdjRib("test", []bgp.RouteFamily{bgp.RF_IPv4_UC, bgp.RF_IPv6_UC}) m1 := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri) peer := peerR1() pList1 := ProcessMessage(m1, peer, time.Now()) |