326 lines
8.0 KiB
Go
326 lines
8.0 KiB
Go
package api
|
|
|
|
import (
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
// A Response is a general API response. All API responses
|
|
// contain meta information with API version and caching
|
|
// information.
|
|
type Response struct {
|
|
Meta *Meta `json:"api"`
|
|
}
|
|
|
|
// ErrorResponse encodes an error message and code
|
|
type ErrorResponse struct {
|
|
Message string `json:"message"`
|
|
Code int `json:"code"`
|
|
Tag string `json:"tag"`
|
|
RouteserverID string `json:"routeserver_id"`
|
|
}
|
|
|
|
// CacheableResponse is a cache aware API response
|
|
type CacheableResponse interface {
|
|
CacheTTL() time.Duration
|
|
}
|
|
|
|
// ConfigResponse is a response with client runtime configuration
|
|
type ConfigResponse struct {
|
|
RejectReasons map[string]interface{} `json:"reject_reasons"`
|
|
|
|
Noexport Noexport `json:"noexport"`
|
|
NoexportReasons map[string]interface{} `json:"noexport_reasons"`
|
|
|
|
RejectCandidates RejectCandidates `json:"reject_candidates"`
|
|
|
|
Rpki Rpki `json:"rpki"`
|
|
|
|
BGPCommunities map[string]interface{} `json:"bgp_communities"`
|
|
BGPBlackholeCommunities BGPCommunitiesSet `json:"bgp_blackhole_communities"`
|
|
|
|
NeighborsColumns map[string]string `json:"neighbors_columns"`
|
|
NeighborsColumnsOrder []string `json:"neighbors_columns_order"`
|
|
|
|
RoutesColumns map[string]string `json:"routes_columns"`
|
|
RoutesColumnsOrder []string `json:"routes_columns_order"`
|
|
|
|
LookupColumns map[string]string `json:"lookup_columns"`
|
|
LookupColumnsOrder []string `json:"lookup_columns_order"`
|
|
|
|
PrefixLookupEnabled bool `json:"prefix_lookup_enabled"`
|
|
}
|
|
|
|
// Noexport options
|
|
type Noexport struct {
|
|
LoadOnDemand bool `json:"load_on_demand"`
|
|
}
|
|
|
|
// RejectCandidates contains a communities mapping
|
|
// of reasons for a rejection in the future.
|
|
type RejectCandidates struct {
|
|
Communities map[string]interface{} `json:"communities"`
|
|
}
|
|
|
|
// Rpki is the validation status of a prefix
|
|
type Rpki struct {
|
|
Enabled bool `json:"enabled"`
|
|
Valid [][]string `json:"valid"`
|
|
Unknown [][]string `json:"unknown"`
|
|
NotChecked [][]string `json:"not_checked"`
|
|
Invalid [][]string `json:"invalid"`
|
|
}
|
|
|
|
// Meta contains response meta information
|
|
// like cacheing time and cache ttl or the API version
|
|
type Meta struct {
|
|
Version string `json:"version"`
|
|
CacheStatus CacheStatus `json:"cache_status"`
|
|
ResultFromCache bool `json:"result_from_cache"`
|
|
TTL time.Time `json:"ttl"`
|
|
StoreStatus *StoreStatusMeta `json:"store_status,omitempty"`
|
|
}
|
|
|
|
// CacheStatus contains cache timing information.
|
|
type CacheStatus struct {
|
|
CachedAt time.Time `json:"cached_at"`
|
|
OrigTTL int `json:"orig_ttl"`
|
|
}
|
|
|
|
// SourceStatus is the current status of a source in
|
|
// a store.
|
|
type SourceStatus struct {
|
|
RefreshInterval time.Duration `json:"refresh_interval"`
|
|
LastRefresh time.Time `json:"last_refresh"`
|
|
State string `json:"state"`
|
|
Initialized bool `json:"initialized"`
|
|
}
|
|
|
|
// StoreStatus is meta data for a store
|
|
type StoreStatus struct {
|
|
Initialized bool `json:"initialized"`
|
|
Sources map[string]*SourceStatus `json:"sources"`
|
|
}
|
|
|
|
// StoreStatusMeta is the meta response for all stores
|
|
type StoreStatusMeta struct {
|
|
Routes *StoreStatus `json:"routes,omitempty"`
|
|
Neighbors *StoreStatus `json:"neighbors,omitempty"`
|
|
}
|
|
|
|
// Status ... TODO: ?
|
|
type Status struct {
|
|
ServerTime time.Time `json:"server_time"`
|
|
LastReboot time.Time `json:"last_reboot"`
|
|
LastReconfig time.Time `json:"last_reconfig"`
|
|
Message string `json:"message"`
|
|
RouterID string `json:"router_id"`
|
|
Version string `json:"version"`
|
|
Backend string `json:"backend"`
|
|
}
|
|
|
|
// StatusResponse ??
|
|
type StatusResponse struct {
|
|
Response
|
|
Status Status `json:"status"`
|
|
}
|
|
|
|
// A RouteServer is a datasource with attributes.
|
|
type RouteServer struct {
|
|
ID string `json:"id"`
|
|
Type string `json:"type"`
|
|
Name string `json:"name"`
|
|
Group string `json:"group"`
|
|
Blackholes []string `json:"blackholes"`
|
|
|
|
Order int `json:"-"`
|
|
}
|
|
|
|
// RouteServers is a collection of routeservers.
|
|
type RouteServers []RouteServer
|
|
|
|
// Len implements sorting interface for routeservers
|
|
func (rs RouteServers) Len() int {
|
|
return len(rs)
|
|
}
|
|
|
|
func (rs RouteServers) Less(i, j int) bool {
|
|
return rs[i].Order < rs[j].Order
|
|
}
|
|
|
|
func (rs RouteServers) Swap(i, j int) {
|
|
rs[i], rs[j] = rs[j], rs[i]
|
|
}
|
|
|
|
// A RouteServersResponse contains a list of routeservers.
|
|
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
|
|
|
|
func (com Community) String() string {
|
|
if len(com) < 1 {
|
|
return ""
|
|
}
|
|
s := ""
|
|
for i, v := range com {
|
|
if i > 0 {
|
|
s += ":"
|
|
}
|
|
s += strconv.Itoa(v)
|
|
}
|
|
return s
|
|
}
|
|
|
|
// Communities is a collection of bgp communities
|
|
type Communities []Community
|
|
|
|
// Unique deduplicates communities.
|
|
/*
|
|
We can skip this. Worst case is, that the
|
|
cardinality is off.
|
|
func (communities Communities) Unique() Communities {
|
|
seen := map[string]bool{}
|
|
result := make(Communities, 0, len(communities))
|
|
|
|
for _, com := range communities {
|
|
key := com.String()
|
|
if _, ok := seen[key]; !ok {
|
|
// We have not seen this community yet
|
|
result = append(result, com)
|
|
seen[key] = true
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
*/
|
|
|
|
// ExtCommunity is a BGP extended community
|
|
type ExtCommunity []interface{}
|
|
|
|
func (com ExtCommunity) String() string {
|
|
if len(com) < 1 {
|
|
return ""
|
|
}
|
|
res := ""
|
|
for i, v := range com {
|
|
if i == 0 {
|
|
res += v.(string)
|
|
continue
|
|
}
|
|
if i > 0 {
|
|
res += ":"
|
|
}
|
|
res += strconv.Itoa(v.(int))
|
|
}
|
|
return res
|
|
}
|
|
|
|
// ExtCommunities is a collection of extended bgp communities.
|
|
type ExtCommunities []ExtCommunity
|
|
|
|
// Unique deduplicates extended communities.
|
|
/*
|
|
func (communities ExtCommunities) Unique() ExtCommunities {
|
|
seen := map[string]bool{}
|
|
result := make(ExtCommunities, 0, len(communities))
|
|
|
|
for _, com := range communities {
|
|
key := com.String()
|
|
if _, ok := seen[key]; !ok {
|
|
// We have not seen this community yet
|
|
result = append(result, com)
|
|
seen[key] = true
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
*/
|
|
|
|
// BGPInfo is a set of BGP attributes
|
|
type BGPInfo struct {
|
|
Origin *string `json:"origin"`
|
|
AsPath []int `json:"as_path"`
|
|
NextHop *string `json:"next_hop"`
|
|
Communities Communities `json:"communities"`
|
|
LargeCommunities Communities `json:"large_communities"`
|
|
ExtCommunities ExtCommunities `json:"ext_communities"`
|
|
LocalPref int `json:"local_pref"`
|
|
Med int `json:"med"`
|
|
}
|
|
|
|
// HasCommunity checks for the presence of a BGP community.
|
|
func (bgp *BGPInfo) HasCommunity(community Community) bool {
|
|
if len(community) != 2 {
|
|
return false // This can never match.
|
|
}
|
|
|
|
for _, com := range bgp.Communities {
|
|
if len(com) != len(community) {
|
|
continue // This can't match.
|
|
}
|
|
|
|
if com[0] == community[0] &&
|
|
com[1] == community[1] {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// HasExtCommunity checks for the presence of an
|
|
// extended community.
|
|
func (bgp *BGPInfo) HasExtCommunity(community ExtCommunity) bool {
|
|
if len(community) != 3 {
|
|
return false // This can never match.
|
|
}
|
|
|
|
for _, com := range bgp.ExtCommunities {
|
|
if len(com) != len(community) {
|
|
continue // This can't match.
|
|
}
|
|
|
|
if com[0] == community[0] &&
|
|
com[1] == community[1] &&
|
|
com[2] == community[2] {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// HasLargeCommunity checks for the presence of a large community.
|
|
func (bgp *BGPInfo) HasLargeCommunity(community Community) bool {
|
|
// TODO: This is an almost 1:1 match to the function above.
|
|
if len(community) != 3 {
|
|
return false // This can never match.
|
|
}
|
|
|
|
for _, com := range bgp.LargeCommunities {
|
|
if len(com) != len(community) {
|
|
continue // This can't match.
|
|
}
|
|
|
|
if com[0] == community[0] &&
|
|
com[1] == community[1] &&
|
|
com[2] == community[2] {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|