263 lines
6.7 KiB
Go
263 lines
6.7 KiB
Go
package api
|
|
|
|
import (
|
|
"encoding/json"
|
|
"log"
|
|
"time"
|
|
)
|
|
|
|
// Route is a prefix with BGP information.
|
|
type Route struct {
|
|
// ID string `json:"id"`
|
|
NeighborID *string `json:"neighbor_id"`
|
|
|
|
Network string `json:"network"`
|
|
Interface *string `json:"interface"`
|
|
Gateway *string `json:"gateway"`
|
|
Metric int `json:"metric"`
|
|
BGP *BGPInfo `json:"bgp"`
|
|
Age time.Duration `json:"age"`
|
|
Type []string `json:"type"` // [BGP, unicast, univ]
|
|
Primary bool `json:"primary"`
|
|
LearntFrom *string `json:"learnt_from"`
|
|
|
|
Details *json.RawMessage `json:"details"`
|
|
}
|
|
|
|
func (r *Route) String() string {
|
|
s, _ := json.Marshal(r)
|
|
return string(s)
|
|
}
|
|
|
|
// MatchSourceID implements Filterable interface for routes
|
|
func (r *Route) MatchSourceID(id string) bool {
|
|
return true // A route has no source info so we exclude this filter
|
|
}
|
|
|
|
// MatchASN is not defined
|
|
func (r *Route) MatchASN(asn int) bool {
|
|
return true // Same here
|
|
}
|
|
|
|
// MatchCommunity checks for the presence of a BGP community
|
|
func (r *Route) MatchCommunity(community Community) bool {
|
|
return r.BGP.HasCommunity(community)
|
|
}
|
|
|
|
// MatchExtCommunity checks for the presence of a BGP extended community
|
|
func (r *Route) MatchExtCommunity(community ExtCommunity) bool {
|
|
return r.BGP.HasExtCommunity(community)
|
|
}
|
|
|
|
// MatchLargeCommunity checks for the presence of a large BGP community
|
|
func (r *Route) MatchLargeCommunity(community Community) bool {
|
|
return r.BGP.HasLargeCommunity(community)
|
|
}
|
|
|
|
// Routes is a collection of routes
|
|
type Routes []*Route
|
|
|
|
func (routes Routes) Len() int {
|
|
return len(routes)
|
|
}
|
|
|
|
func (routes Routes) Less(i, j int) bool {
|
|
return routes[i].Network < routes[j].Network
|
|
}
|
|
|
|
func (routes Routes) Swap(i, j int) {
|
|
routes[i], routes[j] = routes[j], routes[i]
|
|
}
|
|
|
|
// ToLookupRoutes prepares routes for lookup
|
|
func (routes Routes) ToLookupRoutes(
|
|
state string,
|
|
rs *LookupRouteServer,
|
|
neighbors map[string]*Neighbor,
|
|
) LookupRoutes {
|
|
lookupRoutes := make(LookupRoutes, 0, len(routes))
|
|
for _, route := range routes {
|
|
neighbor, ok := neighbors[*route.NeighborID]
|
|
if !ok {
|
|
log.Println("prepare route, neighbor not found:", route.NeighborID)
|
|
continue
|
|
}
|
|
lr := &LookupRoute{
|
|
Route: route,
|
|
State: state,
|
|
Neighbor: neighbor,
|
|
RouteServer: rs,
|
|
}
|
|
lr.Route.Details = nil
|
|
lookupRoutes = append(lookupRoutes, lr)
|
|
}
|
|
return lookupRoutes
|
|
}
|
|
|
|
// RoutesResponse contains all routes from a source
|
|
type RoutesResponse struct {
|
|
Response
|
|
Imported Routes `json:"imported"`
|
|
Filtered Routes `json:"filtered"`
|
|
NotExported Routes `json:"not_exported"`
|
|
}
|
|
|
|
// CacheTTL returns the cache ttl of the response
|
|
func (res *RoutesResponse) CacheTTL() time.Duration {
|
|
now := time.Now().UTC()
|
|
return res.Response.Meta.TTL.Sub(now)
|
|
}
|
|
|
|
// TimedResponse include the duration of the request
|
|
type TimedResponse struct {
|
|
RequestDuration float64 `json:"request_duration_ms"`
|
|
}
|
|
|
|
// Pagination information, including the
|
|
// current page, total pages, page size, etc...
|
|
type Pagination struct {
|
|
Page int `json:"page"`
|
|
PageSize int `json:"page_size"`
|
|
TotalPages int `json:"total_pages"`
|
|
TotalResults int `json:"total_results"`
|
|
}
|
|
|
|
// A PaginatedResponse with pagination info
|
|
type PaginatedResponse struct {
|
|
Pagination Pagination `json:"pagination"`
|
|
}
|
|
|
|
// FilteredResponse includes filters applied and available
|
|
type FilteredResponse struct {
|
|
FiltersAvailable *SearchFilters `json:"filters_available"`
|
|
FiltersApplied *SearchFilters `json:"filters_applied"`
|
|
FiltersNotAvailable []string `json:"filters_not_available"`
|
|
}
|
|
|
|
const (
|
|
// RouteStateFiltered indicates that the route
|
|
// was not accepted by the route server.
|
|
RouteStateFiltered = "filtered"
|
|
// RouteStateImported indicates that the route was
|
|
// imported by the route server.
|
|
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 {
|
|
*Route
|
|
|
|
State string `json:"state"` // Filtered, Imported, ...
|
|
|
|
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
|
|
}
|
|
|
|
// MatchASN matches the neighbor's ASN
|
|
func (r *LookupRoute) MatchASN(asn int) bool {
|
|
return r.Neighbor.MatchASN(asn)
|
|
}
|
|
|
|
// MatchCommunity checks for the presence of a BGP community.
|
|
func (r *LookupRoute) MatchCommunity(community Community) bool {
|
|
return r.Route.BGP.HasCommunity(community)
|
|
}
|
|
|
|
// MatchExtCommunity matches an extended community
|
|
func (r *LookupRoute) MatchExtCommunity(community ExtCommunity) bool {
|
|
return r.Route.BGP.HasExtCommunity(community)
|
|
}
|
|
|
|
// MatchLargeCommunity matches large communities.
|
|
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
|
|
|
|
func (r LookupRoutes) Len() int {
|
|
return len(r)
|
|
}
|
|
|
|
func (r LookupRoutes) Less(i, j int) bool {
|
|
return r[i].Route.Network < r[j].Route.Network
|
|
}
|
|
|
|
func (r LookupRoutes) Swap(i, j int) {
|
|
r[i], r[j] = r[j], r[i]
|
|
}
|
|
|
|
// RoutesLookup contains routes and pagination info
|
|
type RoutesLookup struct {
|
|
Routes LookupRoutes `json:"routes"`
|
|
Pagination Pagination `json:"pagination"`
|
|
}
|
|
|
|
// RoutesLookupResponse is a PaginatedResponse with
|
|
// a set of lookup routes, as the result of a query of
|
|
// a specific route server.
|
|
type RoutesLookupResponse struct {
|
|
Response
|
|
PaginatedResponse
|
|
TimedResponse
|
|
FilteredResponse
|
|
Routes LookupRoutes `json:"routes"`
|
|
}
|
|
|
|
// GlobalRoutesLookupResponse is the result of a routes
|
|
// query across all route servers.
|
|
type GlobalRoutesLookupResponse struct {
|
|
Response
|
|
PaginatedResponse
|
|
TimedResponse
|
|
FilteredResponse
|
|
Routes LookupRoutes `json:"routes"`
|
|
}
|
|
|
|
// A PaginatedRoutesResponse includes routes and pagination
|
|
// information form a single route server
|
|
type PaginatedRoutesResponse struct {
|
|
Response
|
|
PaginatedResponse
|
|
TimedResponse
|
|
FilteredResponse
|
|
RoutesResponse
|
|
}
|
|
|
|
// A PaginatedRoutesLookupResponse TODO
|
|
type PaginatedRoutesLookupResponse struct {
|
|
Response
|
|
TimedResponse
|
|
FilteredResponse
|
|
|
|
Imported *RoutesLookup `json:"imported"`
|
|
Filtered *RoutesLookup `json:"filtered"`
|
|
|
|
Status *StoreStatusMeta `json:"status"`
|
|
}
|