diff options
author | FUJITA Tomonori <fujita.tomonori@gmail.com> | 2019-04-14 22:58:07 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@gmail.com> | 2019-04-16 12:40:36 +0900 |
commit | bec61c4f38344febda7495a35afa02061bb2880b (patch) | |
tree | 352deca93f361a6b60bffb21b2f18fc6b320d301 /pkg | |
parent | 284ef3627d48bfa22afc4228c8f9cfdec737150e (diff) |
server: make ListPath API show filtered paths
This adds the feature to show filtered paths by policies to ListPath
API.
with EnableFiltered in ListPathRequest enabled:
- ListPath for adj-in sets filtered on paths filtered by policys
- ListPath for adj-out includes paths filtered by policys with filtered set.
Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/server/server.go | 52 | ||||
-rw-r--r-- | pkg/server/server_test.go | 245 |
2 files changed, 286 insertions, 11 deletions
diff --git a/pkg/server/server.go b/pkg/server/server.go index c2158aa7..f31235aa 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -905,6 +905,13 @@ func (s *BgpServer) notifyRecvMessageWatcher(peer *peer, timestamp time.Time, ms s.notifyMessageWatcher(peer, timestamp, msg, false) } +func (s *BgpServer) getPossibleBest(peer *peer, family bgp.RouteFamily) []*table.Path { + if peer.isAddPathSendEnabled(family) { + return peer.localRib.GetPathList(peer.TableID(), peer.AS(), []bgp.RouteFamily{family}) + } + return peer.localRib.GetBestPathList(peer.TableID(), peer.AS(), []bgp.RouteFamily{family}) +} + func (s *BgpServer) getBestFromLocal(peer *peer, rfList []bgp.RouteFamily) ([]*table.Path, []*table.Path) { pathList := []*table.Path{} filtered := []*table.Path{} @@ -928,13 +935,7 @@ func (s *BgpServer) getBestFromLocal(peer *peer, rfList []bgp.RouteFamily) ([]*t } for _, family := range peer.toGlobalFamilies(rfList) { - pl := func() []*table.Path { - if peer.isAddPathSendEnabled(family) { - return peer.localRib.GetPathList(peer.TableID(), peer.AS(), []bgp.RouteFamily{family}) - } - return peer.localRib.GetBestPathList(peer.TableID(), peer.AS(), []bgp.RouteFamily{family}) - }() - for _, path := range pl { + for _, path := range s.getPossibleBest(peer, family) { if p := s.filterpath(peer, path, nil); p != nil { pathList = append(pathList, p) } else { @@ -2437,7 +2438,7 @@ func (s *BgpServer) getVrfRib(name string, family bgp.RouteFamily, prefixes []*t return } -func (s *BgpServer) getAdjRib(addr string, family bgp.RouteFamily, in bool, prefixes []*table.LookupPrefix) (rib *table.Table, v []*table.Validation, err error) { +func (s *BgpServer) getAdjRib(addr string, family bgp.RouteFamily, in bool, enableFiltered bool, prefixes []*table.LookupPrefix) (rib *table.Table, filtered map[string]*table.Path, v []*table.Validation, err error) { err = s.mgmtOperation(func() error { peer, ok := s.neighborMap[addr] if !ok { @@ -2447,12 +2448,34 @@ func (s *BgpServer) getAdjRib(addr string, family bgp.RouteFamily, in bool, pref as := peer.AS() var adjRib *table.AdjRib + filtered = make(map[string]*table.Path) if in { adjRib = peer.adjRibIn + if enableFiltered { + for _, path := range peer.adjRibIn.PathList([]bgp.RouteFamily{family}, true) { + if s.policy.ApplyPolicy(peer.TableID(), table.POLICY_DIRECTION_IMPORT, path, &table.PolicyOptions{}) == nil { + filtered[path.GetNlri().String()] = path + } + } + } } else { adjRib = table.NewAdjRib(peer.configuredRFlist()) - accepted, _ := s.getBestFromLocal(peer, peer.configuredRFlist()) - adjRib.Update(accepted) + if enableFiltered { + for _, path := range s.getPossibleBest(peer, family) { + path, options, stop := s.prePolicyFilterpath(peer, path, nil) + if stop { + continue + } + p := peer.policy.ApplyPolicy(peer.TableID(), table.POLICY_DIRECTION_EXPORT, path, options) + if p == nil { + filtered[path.GetNlri().String()] = path + } + adjRib.Update([]*table.Path{path}) + } + } else { + accepted, _ := s.getBestFromLocal(peer, peer.configuredRFlist()) + adjRib.Update(accepted) + } } rib, err = adjRib.Select(family, false, table.TableSelectOption{ID: id, AS: as, LookupPrefixes: prefixes}) v = s.validateTable(rib) @@ -2464,6 +2487,7 @@ func (s *BgpServer) getAdjRib(addr string, family bgp.RouteFamily, in bool, pref func (s *BgpServer) ListPath(ctx context.Context, r *api.ListPathRequest, fn func(*api.Destination)) error { var tbl *table.Table var v []*table.Validation + var filtered map[string]*table.Path f := func() []*table.LookupPrefix { l := make([]*table.LookupPrefix, 0, len(r.Prefixes)) @@ -2489,7 +2513,7 @@ func (s *BgpServer) ListPath(ctx context.Context, r *api.ListPathRequest, fn fun in = true fallthrough case api.TableType_ADJ_OUT: - tbl, v, err = s.getAdjRib(r.Name, family, in, f()) + tbl, filtered, v, err = s.getAdjRib(r.Name, family, in, r.EnableFiltered, f()) case api.TableType_VRF: tbl, err = s.getVrfRib(r.Name, family, []*table.LookupPrefix{}) default: @@ -2522,7 +2546,13 @@ func (s *BgpServer) ListPath(ctx context.Context, r *api.ListPathRequest, fn fun } } d.Paths = append(d.Paths, p) + if r.EnableFiltered { + if _, ok := filtered[path.GetNlri().String()]; ok { + p.Filtered = true + } + } } + select { case <-ctx.Done(): return nil diff --git a/pkg/server/server_test.go b/pkg/server/server_test.go index 20d90edb..33bc1fea 100644 --- a/pkg/server/server_test.go +++ b/pkg/server/server_test.go @@ -209,6 +209,251 @@ func TestListPolicyAssignment(t *testing.T) { assert.Equal(len(ps), 0) } +func TestListPathEnableFiltered(test *testing.T) { + assert := assert.New(test) + s := NewBgpServer() + go s.Serve() + err := s.StartBgp(context.Background(), &api.StartBgpRequest{ + Global: &api.Global{ + As: 1, + RouterId: "1.1.1.1", + ListenPort: 10179, + }, + }) + assert.Nil(err) + defer s.StopBgp(context.Background(), &api.StopBgpRequest{}) + + peer1 := &api.Peer{ + Conf: &api.PeerConf{ + NeighborAddress: "127.0.0.1", + PeerAs: 2, + }, + Transport: &api.Transport{ + PassiveMode: true, + }, + } + err = s.AddPeer(context.Background(), &api.AddPeerRequest{Peer: peer1}) + assert.Nil(err) + + d1 := &api.DefinedSet{ + DefinedType: api.DefinedType_PREFIX, + Name: "d1", + Prefixes: []*api.Prefix{ + &api.Prefix{ + IpPrefix: "10.1.0.0/24", + MaskLengthMax: 24, + MaskLengthMin: 24, + }, + }, + } + s1 := &api.Statement{ + Name: "s1", + Conditions: &api.Conditions{ + PrefixSet: &api.MatchSet{ + Name: "d1", + }, + }, + Actions: &api.Actions{ + RouteAction: api.RouteAction_REJECT, + }, + } + err = s.AddDefinedSet(context.Background(), &api.AddDefinedSetRequest{DefinedSet: d1}) + assert.Nil(err) + p1 := &api.Policy{ + Name: "p1", + Statements: []*api.Statement{s1}, + } + err = s.AddPolicy(context.Background(), &api.AddPolicyRequest{Policy: p1}) + assert.Nil(err) + err = s.AddPolicyAssignment(context.Background(), &api.AddPolicyAssignmentRequest{ + Assignment: &api.PolicyAssignment{ + Name: table.GLOBAL_RIB_NAME, + Direction: api.PolicyDirection_IMPORT, + Policies: []*api.Policy{p1}, + DefaultAction: api.RouteAction_ACCEPT, + }, + }) + assert.Nil(err) + + t := NewBgpServer() + go t.Serve() + err = t.StartBgp(context.Background(), &api.StartBgpRequest{ + Global: &api.Global{ + As: 2, + RouterId: "2.2.2.2", + ListenPort: -1, + }, + }) + assert.Nil(err) + defer t.StopBgp(context.Background(), &api.StopBgpRequest{}) + + family := &api.Family{ + Afi: api.Family_AFI_IP, + Safi: api.Family_SAFI_UNICAST, + } + + nlri1, _ := ptypes.MarshalAny(&api.IPAddressPrefix{ + Prefix: "10.1.0.0", + PrefixLen: 24, + }) + + a1, _ := ptypes.MarshalAny(&api.OriginAttribute{ + Origin: 0, + }) + a2, _ := ptypes.MarshalAny(&api.NextHopAttribute{ + NextHop: "10.0.0.1", + }) + attrs := []*any.Any{a1, a2} + + t.AddPath(context.Background(), &api.AddPathRequest{ + TableType: api.TableType_GLOBAL, + Path: &api.Path{ + Family: family, + Nlri: nlri1, + Pattrs: attrs, + }, + }) + + nlri2, _ := ptypes.MarshalAny(&api.IPAddressPrefix{ + Prefix: "10.2.0.0", + PrefixLen: 24, + }) + t.AddPath(context.Background(), &api.AddPathRequest{ + TableType: api.TableType_GLOBAL, + Path: &api.Path{ + Family: family, + Nlri: nlri2, + Pattrs: attrs, + }, + }) + + peer2 := &api.Peer{ + Conf: &api.PeerConf{ + NeighborAddress: "127.0.0.1", + PeerAs: 1, + }, + Transport: &api.Transport{ + RemotePort: 10179, + }, + } + ch := make(chan struct{}) + go s.MonitorPeer(context.Background(), &api.MonitorPeerRequest{}, func(peer *api.Peer) { + if peer.State.SessionState == api.PeerState_ESTABLISHED { + close(ch) + } + }) + + err = t.AddPeer(context.Background(), &api.AddPeerRequest{Peer: peer2}) + assert.Nil(err) + <-ch + + for { + count := 0 + s.ListPath(context.Background(), &api.ListPathRequest{TableType: api.TableType_ADJ_IN, Family: family, Name: "127.0.0.1"}, func(d *api.Destination) { + count++ + }) + if count == 2 { + break + } + } + count := 0 + s.ListPath(context.Background(), &api.ListPathRequest{TableType: api.TableType_GLOBAL, Family: family}, func(d *api.Destination) { + count++ + }) + assert.Equal(1, count) + + filtered := 0 + s.ListPath(context.Background(), &api.ListPathRequest{TableType: api.TableType_ADJ_IN, Family: family, Name: "127.0.0.1", EnableFiltered: true}, func(d *api.Destination) { + if d.Paths[0].Filtered { + filtered++ + } + }) + assert.Equal(1, filtered) + + d2 := &api.DefinedSet{ + DefinedType: api.DefinedType_PREFIX, + Name: "d2", + Prefixes: []*api.Prefix{ + &api.Prefix{ + IpPrefix: "10.3.0.0/24", + MaskLengthMax: 24, + MaskLengthMin: 24, + }, + }, + } + s2 := &api.Statement{ + Name: "s2", + Conditions: &api.Conditions{ + PrefixSet: &api.MatchSet{ + Name: "d2", + }, + }, + Actions: &api.Actions{ + RouteAction: api.RouteAction_REJECT, + }, + } + err = s.AddDefinedSet(context.Background(), &api.AddDefinedSetRequest{DefinedSet: d2}) + assert.Nil(err) + p2 := &api.Policy{ + Name: "p2", + Statements: []*api.Statement{s2}, + } + err = s.AddPolicy(context.Background(), &api.AddPolicyRequest{Policy: p2}) + assert.Nil(err) + err = s.AddPolicyAssignment(context.Background(), &api.AddPolicyAssignmentRequest{ + Assignment: &api.PolicyAssignment{ + Name: table.GLOBAL_RIB_NAME, + Direction: api.PolicyDirection_EXPORT, + Policies: []*api.Policy{p2}, + DefaultAction: api.RouteAction_ACCEPT, + }, + }) + assert.Nil(err) + + nlri3, _ := ptypes.MarshalAny(&api.IPAddressPrefix{ + Prefix: "10.3.0.0", + PrefixLen: 24, + }) + s.AddPath(context.Background(), &api.AddPathRequest{ + TableType: api.TableType_GLOBAL, + Path: &api.Path{ + Family: family, + Nlri: nlri3, + Pattrs: attrs, + }, + }) + + nlri4, _ := ptypes.MarshalAny(&api.IPAddressPrefix{ + Prefix: "10.4.0.0", + PrefixLen: 24, + }) + s.AddPath(context.Background(), &api.AddPathRequest{ + TableType: api.TableType_GLOBAL, + Path: &api.Path{ + Family: family, + Nlri: nlri4, + Pattrs: attrs, + }, + }) + + count = 0 + s.ListPath(context.Background(), &api.ListPathRequest{TableType: api.TableType_GLOBAL, Family: family}, func(d *api.Destination) { + count++ + }) + assert.Equal(3, count) + + count = 0 + filtered = 0 + s.ListPath(context.Background(), &api.ListPathRequest{TableType: api.TableType_ADJ_OUT, Family: family, Name: "127.0.0.1", EnableFiltered: true}, func(d *api.Destination) { + count++ + if d.Paths[0].Filtered { + filtered++ + } + }) + assert.Equal(2, count) + assert.Equal(1, filtered) +} + func TestMonitor(test *testing.T) { assert := assert.New(test) s := NewBgpServer() |