2017-05-18 12:52:10 +02:00
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
2022-11-25 15:38:38 +01:00
|
|
|
"strconv"
|
2017-05-18 12:52:10 +02:00
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2021-10-15 17:09:52 +02:00
|
|
|
// A Response is a general API response. All API responses
|
|
|
|
// contain meta information with API version and caching
|
|
|
|
// information.
|
2021-10-27 17:54:51 +00:00
|
|
|
type Response struct {
|
|
|
|
Meta *Meta `json:"api"`
|
|
|
|
}
|
2017-05-18 15:26:22 +02:00
|
|
|
|
2021-03-24 14:26:46 +01:00
|
|
|
// ErrorResponse encodes an error message and code
|
2017-05-18 14:44:38 +02:00
|
|
|
type ErrorResponse struct {
|
2018-08-05 18:25:59 +02:00
|
|
|
Message string `json:"message"`
|
|
|
|
Code int `json:"code"`
|
|
|
|
Tag string `json:"tag"`
|
2021-10-15 17:09:52 +02:00
|
|
|
RouteserverID string `json:"routeserver_id"`
|
2017-05-18 14:44:38 +02:00
|
|
|
}
|
|
|
|
|
2021-03-24 14:26:46 +01:00
|
|
|
// CacheableResponse is a cache aware API response
|
2018-07-11 14:07:52 +02:00
|
|
|
type CacheableResponse interface {
|
2021-03-22 17:35:20 +01:00
|
|
|
CacheTTL() time.Duration
|
2018-07-11 14:07:52 +02:00
|
|
|
}
|
|
|
|
|
2021-03-24 14:26:46 +01:00
|
|
|
// ConfigResponse is a response with client runtime configuration
|
2017-05-18 15:23:36 +02:00
|
|
|
type ConfigResponse struct {
|
2018-10-03 19:21:03 +02:00
|
|
|
RejectReasons map[string]interface{} `json:"reject_reasons"`
|
2017-05-18 14:44:38 +02:00
|
|
|
|
2018-10-03 19:21:03 +02:00
|
|
|
Noexport Noexport `json:"noexport"`
|
|
|
|
NoexportReasons map[string]interface{} `json:"noexport_reasons"`
|
2017-05-18 14:44:38 +02:00
|
|
|
|
2018-10-02 15:52:46 +02:00
|
|
|
RejectCandidates RejectCandidates `json:"reject_candidates"`
|
|
|
|
|
2018-09-22 17:56:30 +02:00
|
|
|
Rpki Rpki `json:"rpki"`
|
|
|
|
|
2022-11-17 15:21:52 +01:00
|
|
|
BGPCommunities map[string]interface{} `json:"bgp_communities"`
|
|
|
|
BGPBlackholeCommunities BGPCommunitiesSet `json:"bgp_blackhole_communities"`
|
2018-08-09 22:49:32 +02:00
|
|
|
|
2021-10-15 17:09:52 +02:00
|
|
|
NeighborsColumns map[string]string `json:"neighbors_columns"`
|
|
|
|
NeighborsColumnsOrder []string `json:"neighbors_columns_order"`
|
2018-07-02 15:57:29 +02:00
|
|
|
|
|
|
|
RoutesColumns map[string]string `json:"routes_columns"`
|
|
|
|
RoutesColumnsOrder []string `json:"routes_columns_order"`
|
2017-07-04 12:36:48 +02:00
|
|
|
|
2018-08-03 10:37:05 +02:00
|
|
|
LookupColumns map[string]string `json:"lookup_columns"`
|
|
|
|
LookupColumnsOrder []string `json:"lookup_columns_order"`
|
|
|
|
|
2017-07-04 12:36:48 +02:00
|
|
|
PrefixLookupEnabled bool `json:"prefix_lookup_enabled"`
|
2017-05-18 14:44:38 +02:00
|
|
|
}
|
|
|
|
|
2021-03-24 14:26:46 +01:00
|
|
|
// Noexport options
|
2017-05-18 14:44:38 +02:00
|
|
|
type Noexport struct {
|
2018-08-03 14:38:32 +02:00
|
|
|
LoadOnDemand bool `json:"load_on_demand"`
|
2017-05-18 14:44:38 +02:00
|
|
|
}
|
|
|
|
|
2021-10-15 17:09:52 +02:00
|
|
|
// RejectCandidates contains a communities mapping
|
|
|
|
// of reasons for a rejection in the future.
|
2018-10-02 15:52:46 +02:00
|
|
|
type RejectCandidates struct {
|
|
|
|
Communities map[string]interface{} `json:"communities"`
|
|
|
|
}
|
|
|
|
|
2021-10-15 17:09:52 +02:00
|
|
|
// Rpki is the validation status of a prefix
|
2018-09-22 17:56:30 +02:00
|
|
|
type Rpki struct {
|
2023-11-28 14:34:12 +01:00
|
|
|
Enabled bool `json:"enabled"`
|
|
|
|
Valid [][]string `json:"valid"`
|
|
|
|
Unknown [][]string `json:"unknown"`
|
|
|
|
NotChecked [][]string `json:"not_checked"`
|
|
|
|
Invalid [][]string `json:"invalid"`
|
2018-09-22 17:56:30 +02:00
|
|
|
}
|
|
|
|
|
2021-10-15 17:09:52 +02:00
|
|
|
// Meta contains response meta information
|
|
|
|
// like cacheing time and cache ttl or the API version
|
|
|
|
type Meta struct {
|
2022-07-27 18:00:31 +02:00
|
|
|
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"`
|
2017-05-18 12:52:10 +02:00
|
|
|
}
|
|
|
|
|
2021-10-15 17:09:52 +02:00
|
|
|
// CacheStatus contains cache timing information.
|
2017-05-18 12:52:10 +02:00
|
|
|
type CacheStatus struct {
|
|
|
|
CachedAt time.Time `json:"cached_at"`
|
2021-10-15 17:09:52 +02:00
|
|
|
OrigTTL int `json:"orig_ttl"`
|
2017-05-18 12:52:10 +02:00
|
|
|
}
|
|
|
|
|
2022-07-27 18:00:31 +02:00
|
|
|
// 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"`
|
|
|
|
}
|
|
|
|
|
2021-10-15 17:09:52 +02:00
|
|
|
// Status ... TODO: ?
|
2017-05-18 12:52:10 +02:00
|
|
|
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"`
|
2021-10-15 17:09:52 +02:00
|
|
|
RouterID string `json:"router_id"`
|
2017-05-18 12:52:10 +02:00
|
|
|
Version string `json:"version"`
|
|
|
|
Backend string `json:"backend"`
|
|
|
|
}
|
|
|
|
|
2021-10-15 17:09:52 +02:00
|
|
|
// StatusResponse ??
|
2017-05-18 12:52:10 +02:00
|
|
|
type StatusResponse struct {
|
2021-10-27 17:54:51 +00:00
|
|
|
Response
|
2021-10-15 17:09:52 +02:00
|
|
|
Status Status `json:"status"`
|
2017-05-18 12:52:10 +02:00
|
|
|
}
|
|
|
|
|
2021-10-15 17:09:52 +02:00
|
|
|
// A RouteServer is a datasource with attributes.
|
|
|
|
type RouteServer struct {
|
|
|
|
ID string `json:"id"`
|
2021-07-02 14:16:13 +02:00
|
|
|
Type string `json:"type"`
|
2018-09-17 18:12:49 +02:00
|
|
|
Name string `json:"name"`
|
2018-10-21 11:29:43 +02:00
|
|
|
Group string `json:"group"`
|
2018-09-17 18:12:49 +02:00
|
|
|
Blackholes []string `json:"blackholes"`
|
2018-12-09 18:47:40 +01:00
|
|
|
|
|
|
|
Order int `json:"-"`
|
|
|
|
}
|
|
|
|
|
2021-10-15 17:09:52 +02:00
|
|
|
// RouteServers is a collection of routeservers.
|
|
|
|
type RouteServers []RouteServer
|
2018-12-09 18:47:40 +01:00
|
|
|
|
2021-10-15 17:09:52 +02:00
|
|
|
// Len implements sorting interface for routeservers
|
|
|
|
func (rs RouteServers) Len() int {
|
2018-12-09 18:47:40 +01:00
|
|
|
return len(rs)
|
|
|
|
}
|
|
|
|
|
2021-10-15 17:09:52 +02:00
|
|
|
func (rs RouteServers) Less(i, j int) bool {
|
2018-12-09 18:47:40 +01:00
|
|
|
return rs[i].Order < rs[j].Order
|
|
|
|
}
|
|
|
|
|
2021-10-15 17:09:52 +02:00
|
|
|
func (rs RouteServers) Swap(i, j int) {
|
2018-12-09 18:47:40 +01:00
|
|
|
rs[i], rs[j] = rs[j], rs[i]
|
2017-05-18 12:52:10 +02:00
|
|
|
}
|
|
|
|
|
2021-10-15 17:09:52 +02:00
|
|
|
// A RouteServersResponse contains a list of routeservers.
|
|
|
|
type RouteServersResponse struct {
|
|
|
|
RouteServers RouteServers `json:"routeservers"`
|
2017-05-18 12:52:10 +02:00
|
|
|
}
|
|
|
|
|
2024-01-12 11:34:05 +01:00
|
|
|
// A LookupRouteServer is a shorter representation of the
|
|
|
|
// route server data source.
|
|
|
|
type LookupRouteServer struct {
|
|
|
|
ID *string `json:"id"`
|
|
|
|
Name string `json:"name"`
|
|
|
|
}
|
|
|
|
|
2021-10-15 17:09:52 +02:00
|
|
|
// Community is a BGP community
|
2017-05-18 12:52:10 +02:00
|
|
|
type Community []int
|
2018-10-16 18:21:20 +02:00
|
|
|
|
|
|
|
func (com Community) String() string {
|
2022-06-20 16:42:20 +02:00
|
|
|
if len(com) < 1 {
|
|
|
|
return ""
|
|
|
|
}
|
2022-11-25 15:38:38 +01:00
|
|
|
s := ""
|
|
|
|
for i, v := range com {
|
|
|
|
if i > 0 {
|
|
|
|
s += ":"
|
|
|
|
}
|
|
|
|
s += strconv.Itoa(v)
|
2018-10-16 18:21:20 +02:00
|
|
|
}
|
2022-11-25 15:38:38 +01:00
|
|
|
return s
|
2018-10-16 18:21:20 +02:00
|
|
|
}
|
|
|
|
|
2021-10-15 17:09:52 +02:00
|
|
|
// Communities is a collection of bgp communities
|
2018-11-11 17:48:34 +01:00
|
|
|
type Communities []Community
|
|
|
|
|
2022-11-25 15:38:38 +01:00
|
|
|
// Unique deduplicates communities.
|
|
|
|
/*
|
|
|
|
We can skip this. Worst case is, that the
|
|
|
|
cardinality is off.
|
2018-11-11 17:48:34 +01:00
|
|
|
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
|
|
|
|
}
|
2022-11-25 15:38:38 +01:00
|
|
|
*/
|
2018-11-11 17:48:34 +01:00
|
|
|
|
2021-10-15 17:09:52 +02:00
|
|
|
// ExtCommunity is a BGP extended community
|
2018-10-08 14:24:41 +02:00
|
|
|
type ExtCommunity []interface{}
|
2017-05-18 12:52:10 +02:00
|
|
|
|
2018-10-16 18:21:20 +02:00
|
|
|
func (com ExtCommunity) String() string {
|
2022-06-20 16:42:20 +02:00
|
|
|
if len(com) < 1 {
|
|
|
|
return ""
|
|
|
|
}
|
2022-11-25 15:38:38 +01:00
|
|
|
res := ""
|
|
|
|
for i, v := range com {
|
|
|
|
if i == 0 {
|
|
|
|
res += v.(string)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if i > 0 {
|
|
|
|
res += ":"
|
|
|
|
}
|
|
|
|
res += strconv.Itoa(v.(int))
|
2018-10-16 18:21:20 +02:00
|
|
|
}
|
2022-11-25 15:38:38 +01:00
|
|
|
return res
|
2018-10-16 18:21:20 +02:00
|
|
|
}
|
|
|
|
|
2021-10-15 17:09:52 +02:00
|
|
|
// ExtCommunities is a collection of extended bgp communities.
|
2018-11-11 17:48:34 +01:00
|
|
|
type ExtCommunities []ExtCommunity
|
|
|
|
|
2021-10-15 17:09:52 +02:00
|
|
|
// Unique deduplicates extended communities.
|
2022-11-25 15:38:38 +01:00
|
|
|
/*
|
2018-11-11 17:48:34 +01:00
|
|
|
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
|
|
|
|
}
|
2022-11-25 15:38:38 +01:00
|
|
|
*/
|
2018-11-11 17:48:34 +01:00
|
|
|
|
2021-10-15 17:09:52 +02:00
|
|
|
// BGPInfo is a set of BGP attributes
|
|
|
|
type BGPInfo struct {
|
2022-11-16 10:25:02 +01:00
|
|
|
Origin *string `json:"origin"`
|
2018-10-08 14:24:41 +02:00
|
|
|
AsPath []int `json:"as_path"`
|
2022-11-16 10:25:02 +01:00
|
|
|
NextHop *string `json:"next_hop"`
|
2018-11-11 17:48:34 +01:00
|
|
|
Communities Communities `json:"communities"`
|
|
|
|
LargeCommunities Communities `json:"large_communities"`
|
|
|
|
ExtCommunities ExtCommunities `json:"ext_communities"`
|
2018-10-08 14:24:41 +02:00
|
|
|
LocalPref int `json:"local_pref"`
|
|
|
|
Med int `json:"med"`
|
2017-05-18 12:52:10 +02:00
|
|
|
}
|
|
|
|
|
2021-10-15 17:09:52 +02:00
|
|
|
// HasCommunity checks for the presence of a BGP community.
|
|
|
|
func (bgp *BGPInfo) HasCommunity(community Community) bool {
|
2018-10-17 11:05:48 +02:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2021-10-15 17:09:52 +02:00
|
|
|
// HasExtCommunity checks for the presence of an
|
|
|
|
// extended community.
|
|
|
|
func (bgp *BGPInfo) HasExtCommunity(community ExtCommunity) bool {
|
2018-10-17 11:05:48 +02:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2021-10-15 17:09:52 +02:00
|
|
|
// HasLargeCommunity checks for the presence of a large community.
|
|
|
|
func (bgp *BGPInfo) HasLargeCommunity(community Community) bool {
|
2018-10-17 11:05:48 +02:00
|
|
|
// 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
|
|
|
|
}
|