FIX: In some cases the search returned routes for neighbors not queried for.
This commit is contained in:
parent
e6c4b42bfc
commit
6c5c7ea14f
@ -157,6 +157,13 @@ type RouteServersResponse struct {
|
||||
RouteServers RouteServers `json:"routeservers"`
|
||||
}
|
||||
|
||||
// A LookupRouteServer is a shorter representation of the
|
||||
// route server data source.
|
||||
type LookupRouteServer struct {
|
||||
ID *string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// Community is a BGP community
|
||||
type Community []int
|
||||
|
||||
|
@ -72,7 +72,7 @@ func (routes Routes) Swap(i, j int) {
|
||||
// ToLookupRoutes prepares routes for lookup
|
||||
func (routes Routes) ToLookupRoutes(
|
||||
state string,
|
||||
rs *RouteServer,
|
||||
rs *LookupRouteServer,
|
||||
neighbors map[string]*Neighbor,
|
||||
) LookupRoutes {
|
||||
lookupRoutes := make(LookupRoutes, 0, len(routes))
|
||||
@ -142,6 +142,13 @@ const (
|
||||
RouteStateImported = "imported"
|
||||
)
|
||||
|
||||
// NeighborQuery is used in finding routes by neighbors.
|
||||
// Source and Neighbor IDs are pointers to string pools.
|
||||
type NeighborQuery struct {
|
||||
NeighborID *string
|
||||
SourceID *string
|
||||
}
|
||||
|
||||
// LookupRoute is a route with additional
|
||||
// neighbor and state information
|
||||
type LookupRoute struct {
|
||||
@ -149,13 +156,13 @@ type LookupRoute struct {
|
||||
|
||||
State string `json:"state"` // Filtered, Imported, ...
|
||||
|
||||
Neighbor *Neighbor `json:"neighbor"`
|
||||
RouteServer *RouteServer `json:"routeserver"`
|
||||
Neighbor *Neighbor `json:"neighbor"`
|
||||
RouteServer *LookupRouteServer `json:"routeserver"`
|
||||
}
|
||||
|
||||
// MatchSourceID implements filterable interface for lookup routes
|
||||
func (r *LookupRoute) MatchSourceID(id string) bool {
|
||||
return r.RouteServer.ID == id
|
||||
return *r.RouteServer.ID == id
|
||||
}
|
||||
|
||||
// MatchASN matches the neighbor's ASN
|
||||
@ -178,6 +185,17 @@ func (r *LookupRoute) MatchLargeCommunity(community Community) bool {
|
||||
return r.Route.BGP.HasLargeCommunity(community)
|
||||
}
|
||||
|
||||
// MatchNeighborQuery matches a neighbor query
|
||||
func (r *LookupRoute) MatchNeighborQuery(query *NeighborQuery) bool {
|
||||
if r.RouteServer.ID != query.SourceID {
|
||||
return false
|
||||
}
|
||||
if r.NeighborID != query.NeighborID {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// LookupRoutes is a collection of lookup routes.
|
||||
type LookupRoutes []*LookupRoute
|
||||
|
||||
|
@ -48,7 +48,32 @@ func searchFilterCmpInt(a FilterValue, b FilterValue) bool {
|
||||
|
||||
// Compare strings
|
||||
func searchFilterCmpString(a FilterValue, b FilterValue) bool {
|
||||
return a.(string) == b.(string)
|
||||
var (
|
||||
valA string
|
||||
valB string
|
||||
)
|
||||
_, ptrA := a.(*string)
|
||||
_, ptrB := b.(*string)
|
||||
|
||||
// Compare pointers, this is ok because we can assume
|
||||
// using pool values for both.
|
||||
if ptrA && ptrB {
|
||||
return a == b
|
||||
}
|
||||
|
||||
// Otherwise fall back to string compare
|
||||
if ptrA {
|
||||
valA = *a.(*string)
|
||||
} else {
|
||||
valA = a.(string)
|
||||
}
|
||||
if ptrB {
|
||||
valB = *b.(*string)
|
||||
} else {
|
||||
valB = b.(string)
|
||||
}
|
||||
|
||||
return valA == valB
|
||||
}
|
||||
|
||||
// Compare communities
|
||||
@ -136,6 +161,8 @@ func filterValueAsString(value interface{}) string {
|
||||
switch v := value.(type) {
|
||||
case int:
|
||||
return strconv.Itoa(v)
|
||||
case *string:
|
||||
return *v
|
||||
case string:
|
||||
return v
|
||||
case Community:
|
||||
|
@ -5,6 +5,10 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
testRsID string = "3"
|
||||
)
|
||||
|
||||
func makeTestRoute() *Route {
|
||||
route := &Route{
|
||||
BGP: &BGPInfo{
|
||||
@ -44,8 +48,8 @@ func makeTestLookupRoute() *LookupRoute {
|
||||
ASN: 23042,
|
||||
Description: "Security Solutions Ltd.",
|
||||
},
|
||||
RouteServer: &RouteServer{
|
||||
ID: "3",
|
||||
RouteServer: &LookupRouteServer{
|
||||
ID: &testRsID,
|
||||
Name: "test.rs.ixp",
|
||||
},
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import (
|
||||
|
||||
"github.com/alice-lg/alice-lg/pkg/api"
|
||||
"github.com/alice-lg/alice-lg/pkg/decoders"
|
||||
"github.com/alice-lg/alice-lg/pkg/pools"
|
||||
"github.com/alice-lg/alice-lg/pkg/sources"
|
||||
"github.com/alice-lg/alice-lg/pkg/sources/birdwatcher"
|
||||
"github.com/alice-lg/alice-lg/pkg/sources/gobgp"
|
||||
@ -747,6 +748,9 @@ func getSources(config *ini.File) ([]*SourceConfig, error) {
|
||||
Type: sourceType,
|
||||
}
|
||||
|
||||
// Register route server ID with pool
|
||||
pools.RouteServers.Acquire(sourceID)
|
||||
|
||||
// Set backend
|
||||
switch backendType {
|
||||
case SourceBackendBirdwatcher:
|
||||
|
@ -7,6 +7,9 @@ import "log"
|
||||
// Default pools: These pools are defined globally
|
||||
// and are defined per intended usage
|
||||
|
||||
// RouteServers stores route server IDs
|
||||
var RouteServers *StringPool
|
||||
|
||||
// Neighbors stores neighbor IDs
|
||||
var Neighbors *StringPool
|
||||
|
||||
@ -47,6 +50,7 @@ var LargeCommunities *CommunitiesPool
|
||||
func init() {
|
||||
log.Println("initializing memory pools")
|
||||
|
||||
RouteServers = NewStringPool()
|
||||
Neighbors = NewStringPool()
|
||||
Networks4 = NewStringPool()
|
||||
Networks6 = NewStringPool()
|
||||
|
@ -213,7 +213,7 @@ func (b *RoutesBackend) CountRoutesAt(
|
||||
// list of neighbors identified by ID.
|
||||
func (b *RoutesBackend) FindByNeighbors(
|
||||
ctx context.Context,
|
||||
neighborIDs []string,
|
||||
neighbors []*api.NeighborQuery,
|
||||
) (api.LookupRoutes, error) {
|
||||
tx, err := b.pool.BeginTx(ctx, pgx.TxOptions{
|
||||
IsoLevel: pgx.ReadCommitted,
|
||||
@ -223,23 +223,22 @@ func (b *RoutesBackend) FindByNeighbors(
|
||||
}
|
||||
defer tx.Rollback(ctx)
|
||||
|
||||
vals := make([]interface{}, len(neighborIDs))
|
||||
for i := range neighborIDs {
|
||||
vals[i] = neighborIDs[i]
|
||||
}
|
||||
vars := make([]string, len(neighborIDs))
|
||||
for i := range neighborIDs {
|
||||
vars[i] = fmt.Sprintf("$%d", i+1)
|
||||
}
|
||||
listQry := strings.Join(vars, ",")
|
||||
vals := make([]interface{}, 0, len(neighbors))
|
||||
vars := 0
|
||||
|
||||
qrys := []string{}
|
||||
for _, src := range b.sources {
|
||||
tbl := b.routesTable(src.ID)
|
||||
|
||||
for _, neighborQuery := range neighbors {
|
||||
tbl := b.routesTable(*neighborQuery.SourceID)
|
||||
param := fmt.Sprintf("$%d", vars+1)
|
||||
vals = append(vals, *neighborQuery.NeighborID)
|
||||
|
||||
qry := `
|
||||
SELECT route FROM ` + tbl + `
|
||||
WHERE neighbor_id IN (` + listQry + `)`
|
||||
WHERE neighbor_id = ` + param
|
||||
qrys = append(qrys, qry)
|
||||
|
||||
vars++
|
||||
}
|
||||
|
||||
qry := strings.Join(qrys, " UNION ")
|
||||
|
@ -113,9 +113,16 @@ func TestFindByNeighbors(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
routes, err := b.FindByNeighbors(ctx, []string{
|
||||
"n24", "n25",
|
||||
})
|
||||
nq1 := &api.NeighborQuery{
|
||||
NeighborID: pools.Neighbors.Acquire("n24"),
|
||||
SourceID: pools.RouteServers.Acquire("rs1"),
|
||||
}
|
||||
nq2 := &api.NeighborQuery{
|
||||
NeighborID: pools.Neighbors.Acquire("n25"),
|
||||
SourceID: pools.RouteServers.Acquire("rs2"),
|
||||
}
|
||||
|
||||
routes, err := b.FindByNeighbors(ctx, []*api.NeighborQuery{nq1, nq2})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -247,8 +247,6 @@ func (s *NeighborsStore) lookupNeighborsAt(
|
||||
sourceID string,
|
||||
query string,
|
||||
) (api.Neighbors, error) {
|
||||
|
||||
results := api.Neighbors{}
|
||||
neighbors, err := s.backend.GetNeighborsAt(ctx, sourceID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -262,6 +260,7 @@ func (s *NeighborsStore) lookupNeighborsAt(
|
||||
}
|
||||
}
|
||||
|
||||
results := api.Neighbors{}
|
||||
for _, neighbor := range neighbors {
|
||||
if asn >= 0 && neighbor.ASN == asn { // only executed if valid AS query is detected
|
||||
results = append(results, neighbor)
|
||||
|
@ -9,9 +9,27 @@ import (
|
||||
|
||||
"github.com/alice-lg/alice-lg/pkg/api"
|
||||
"github.com/alice-lg/alice-lg/pkg/config"
|
||||
"github.com/alice-lg/alice-lg/pkg/pools"
|
||||
"github.com/alice-lg/alice-lg/pkg/sources"
|
||||
)
|
||||
|
||||
// newNeighborQuery creates a new NeighborQuery
|
||||
func newNeighborQuery(neighborID string, sourceID string) *api.NeighborQuery {
|
||||
ptrNeighborID := pools.Neighbors.Get(neighborID)
|
||||
if ptrNeighborID == nil {
|
||||
return nil
|
||||
}
|
||||
ptrSourceID := pools.RouteServers.Get(sourceID)
|
||||
if ptrSourceID == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &api.NeighborQuery{
|
||||
NeighborID: ptrNeighborID,
|
||||
SourceID: ptrSourceID,
|
||||
}
|
||||
}
|
||||
|
||||
// RoutesStoreBackend interface
|
||||
type RoutesStoreBackend interface {
|
||||
// SetRoutes updates the routes in the store after a refresh.
|
||||
@ -33,7 +51,7 @@ type RoutesStoreBackend interface {
|
||||
// announced by the neighbor at a given source
|
||||
FindByNeighbors(
|
||||
ctx context.Context,
|
||||
neighborIDs []string,
|
||||
neighbors []*api.NeighborQuery,
|
||||
) (api.LookupRoutes, error)
|
||||
|
||||
// FindByPrefix
|
||||
@ -182,8 +200,8 @@ func (s *RoutesStore) updateSource(
|
||||
"accepted and", len(res.Filtered), "filtered routes for:", src.Name)
|
||||
|
||||
// Prepare imported routes for lookup
|
||||
srcRS := &api.RouteServer{
|
||||
ID: src.ID,
|
||||
srcRS := &api.LookupRouteServer{
|
||||
ID: pools.RouteServers.Acquire(src.ID),
|
||||
Name: src.Name,
|
||||
}
|
||||
imported := res.Imported.ToLookupRoutes("imported", srcRS, neighbors)
|
||||
@ -320,11 +338,16 @@ func (s *RoutesStore) LookupPrefixForNeighbors(
|
||||
ctx context.Context,
|
||||
neighbors api.NeighborsLookupResults,
|
||||
) (api.LookupRoutes, error) {
|
||||
neighborIDs := []string{}
|
||||
for _, rs := range neighbors {
|
||||
for _, neighbor := range rs {
|
||||
neighborIDs = append(neighborIDs, neighbor.ID)
|
||||
query := make([]*api.NeighborQuery, 0, len(neighbors))
|
||||
|
||||
for sourceID, sourceNeighbors := range neighbors {
|
||||
for _, neighbor := range sourceNeighbors {
|
||||
q := newNeighborQuery(neighbor.ID, sourceID)
|
||||
if q == nil {
|
||||
continue
|
||||
}
|
||||
query = append(query, q)
|
||||
}
|
||||
}
|
||||
return s.backend.FindByNeighbors(ctx, neighborIDs)
|
||||
return s.backend.FindByNeighbors(ctx, query)
|
||||
}
|
||||
|
@ -29,8 +29,8 @@ func importRoutes(
|
||||
ID: "ID7254_AS31334",
|
||||
},
|
||||
}
|
||||
srcRS := &api.RouteServer{
|
||||
ID: src.ID,
|
||||
srcRS := &api.LookupRouteServer{
|
||||
ID: pools.RouteServers.Acquire(src.ID),
|
||||
Name: src.Name,
|
||||
}
|
||||
imported := res.Imported.ToLookupRoutes("imported", srcRS, neighbors)
|
||||
|
4
pkg/store/testdata/testdata.go
vendored
4
pkg/store/testdata/testdata.go
vendored
@ -42,8 +42,8 @@ func LoadTestLookupRoutes(srcID, srcName string) api.LookupRoutes {
|
||||
ID: "ID7254_AS31334",
|
||||
},
|
||||
}
|
||||
rs := &api.RouteServer{
|
||||
ID: srcID,
|
||||
rs := &api.LookupRouteServer{
|
||||
ID: pools.RouteServers.Acquire(srcID),
|
||||
Name: srcName,
|
||||
}
|
||||
imported := res.Imported.ToLookupRoutes("imported", rs, neighbors)
|
||||
|
Loading…
x
Reference in New Issue
Block a user