mirror of
https://github.com/alice-lg/birdwatcher.git
synced 2025-03-09 00:00:05 +01:00
Merge branch 'DECIX-release/1.13.0'
This commit is contained in:
commit
dd9475f2e8
7 changed files with 168 additions and 133 deletions
104
bird/bird.go
104
bird/bird.go
|
@ -229,7 +229,6 @@ func Protocols() (Parsed, bool) {
|
|||
|
||||
for key, _ := range (*p)["protocols"].(Parsed) {
|
||||
parsed := (*p)["protocols"].(Parsed)[key].(Parsed)
|
||||
|
||||
protocol := parsed["protocol"].(string)
|
||||
|
||||
birdProtocol := parsed["bird_protocol"].(string)
|
||||
|
@ -281,6 +280,16 @@ func RoutesProto(protocol string) (Parsed, bool) {
|
|||
return RunAndParse(GetCacheKey("RoutesProto", protocol), cmd, parseRoutes, nil)
|
||||
}
|
||||
|
||||
func RoutesPeer(peer string) (Parsed, bool) {
|
||||
cmd := routeQueryForChannel("route all where from=" + peer)
|
||||
return RunAndParse(GetCacheKey("RoutesPeer", peer), cmd, parseRoutes, nil)
|
||||
}
|
||||
|
||||
func RoutesTableAndPeer(table string, peer string) (Parsed, bool) {
|
||||
cmd := routeQueryForChannel("route table " + table + " all where from=" + peer)
|
||||
return RunAndParse(GetCacheKey("RoutesTableAndPeer", table, peer), cmd, parseRoutes, nil)
|
||||
}
|
||||
|
||||
func RoutesProtoCount(protocol string) (Parsed, bool) {
|
||||
cmd := routeQueryForChannel("route protocol "+protocol) + " count"
|
||||
return RunAndParse(GetCacheKey("RoutesProtoCount", protocol), cmd, parseRoutesCount, nil)
|
||||
|
@ -312,16 +321,6 @@ func RoutesExport(protocol string) (Parsed, bool) {
|
|||
}
|
||||
|
||||
func RoutesNoExport(protocol string) (Parsed, bool) {
|
||||
// In case we have a multi table setup, we have to query
|
||||
// the pipe protocol.
|
||||
if ParserConf.PerPeerTables &&
|
||||
strings.HasPrefix(protocol, ParserConf.PeerProtocolPrefix) {
|
||||
|
||||
// Replace prefix
|
||||
protocol = ParserConf.PipeProtocolPrefix +
|
||||
protocol[len(ParserConf.PeerProtocolPrefix):]
|
||||
}
|
||||
|
||||
cmd := routeQueryForChannel("route all noexport " + protocol)
|
||||
return RunAndParse(GetCacheKey("RoutesNoExport", protocol), cmd, parseRoutes, nil)
|
||||
}
|
||||
|
@ -335,6 +334,10 @@ func RoutesTable(table string) (Parsed, bool) {
|
|||
return RunAndParse(GetCacheKey("RoutesTable", table), "route table "+table+" all", parseRoutes, nil)
|
||||
}
|
||||
|
||||
func RoutesTableFiltered(table string) (Parsed, bool) {
|
||||
return RunAndParse(GetCacheKey("RoutesTableFiltered", table), "route table "+table+" filtered", parseRoutes, nil)
|
||||
}
|
||||
|
||||
func RoutesTableCount(table string) (Parsed, bool) {
|
||||
return RunAndParse(GetCacheKey("RoutesTableCount", table), "route table "+table+" count", parseRoutesCount, nil)
|
||||
}
|
||||
|
@ -347,85 +350,6 @@ func RoutesLookupProtocol(net string, protocol string) (Parsed, bool) {
|
|||
return RunAndParse(GetCacheKey("RoutesLookupProtocol", net, protocol), "route for "+net+" protocol "+protocol+" all", parseRoutes, nil)
|
||||
}
|
||||
|
||||
func RoutesPeer(peer string) (Parsed, bool) {
|
||||
cmd := routeQueryForChannel("route export " + peer)
|
||||
return RunAndParse(GetCacheKey("RoutesPeer", peer), cmd, parseRoutes, nil)
|
||||
}
|
||||
|
||||
func RoutesDump() (Parsed, bool) {
|
||||
// TODO insert hook to update the cache with the route count information
|
||||
if ParserConf.PerPeerTables {
|
||||
return RoutesDumpPerPeerTable()
|
||||
}
|
||||
|
||||
return RoutesDumpSingleTable()
|
||||
}
|
||||
|
||||
func RoutesDumpSingleTable() (Parsed, bool) {
|
||||
importedRes, cached := RunAndParse(GetCacheKey("RoutesDumpSingleTable", "imported"), routeQueryForChannel("route all"), parseRoutes, nil)
|
||||
if IsSpecial(importedRes) {
|
||||
return importedRes, cached
|
||||
}
|
||||
filteredRes, cached := RunAndParse(GetCacheKey("RoutesDumpSingleTable", "filtered"), routeQueryForChannel("route all filtered"), parseRoutes, nil)
|
||||
if IsSpecial(filteredRes) {
|
||||
return filteredRes, cached
|
||||
}
|
||||
|
||||
imported := importedRes["routes"]
|
||||
filtered := filteredRes["routes"]
|
||||
|
||||
result := Parsed{
|
||||
"imported": imported,
|
||||
"filtered": filtered,
|
||||
}
|
||||
|
||||
return result, cached
|
||||
}
|
||||
|
||||
func RoutesDumpPerPeerTable() (Parsed, bool) {
|
||||
importedRes, cached := RunAndParse(GetCacheKey("RoutesDumpPerPeerTable", "imported"), routeQueryForChannel("route all"), parseRoutes, nil)
|
||||
if IsSpecial(importedRes) {
|
||||
return importedRes, cached
|
||||
}
|
||||
imported := importedRes["routes"]
|
||||
filtered := []Parsed{}
|
||||
|
||||
// Get protocols with filtered routes
|
||||
protocolsRes, cached := ProtocolsBgp()
|
||||
if IsSpecial(protocolsRes) {
|
||||
return protocolsRes, cached
|
||||
}
|
||||
protocols := protocolsRes["protocols"].(Parsed)
|
||||
|
||||
for protocol, details := range protocols {
|
||||
details := details.(Parsed)
|
||||
|
||||
counters, ok := details["routes"].(Parsed)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
filterCount := counters["filtered"]
|
||||
if filterCount == 0 {
|
||||
continue // nothing to do here.
|
||||
}
|
||||
// Lookup filtered routes
|
||||
pfilteredRes, _ := RoutesFiltered(protocol)
|
||||
pfiltered, ok := pfilteredRes["routes"].([]Parsed)
|
||||
if !ok {
|
||||
continue // something went wrong...
|
||||
}
|
||||
|
||||
filtered = append(filtered, pfiltered...)
|
||||
}
|
||||
|
||||
result := Parsed{
|
||||
"imported": imported,
|
||||
"filtered": filtered,
|
||||
}
|
||||
|
||||
return result, cached
|
||||
}
|
||||
|
||||
func routeQueryForChannel(cmd string) string {
|
||||
status, _ := Status()
|
||||
if IsSpecial(status) {
|
||||
|
|
|
@ -17,10 +17,7 @@ type BirdConfig struct {
|
|||
}
|
||||
|
||||
type ParserConfig struct {
|
||||
FilterFields []string `toml:"filter_fields"`
|
||||
PerPeerTables bool `toml:"per_peer_tables"`
|
||||
PeerProtocolPrefix string `toml:"peer_protocol_prefix"`
|
||||
PipeProtocolPrefix string `toml:"pipe_protocol_prefix"`
|
||||
FilterFields []string `toml:"filter_fields"`
|
||||
}
|
||||
|
||||
type RateLimitConfig struct {
|
||||
|
|
|
@ -542,6 +542,7 @@ func parseProtocol(lines string) Parsed {
|
|||
routes := Parsed{}
|
||||
routes["accepted"] = int64(0)
|
||||
routes["filtered"] = int64(0)
|
||||
routes["imported"] = int64(0)
|
||||
routes["exported"] = int64(0)
|
||||
routes["preferred"] = int64(0)
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ import (
|
|||
)
|
||||
|
||||
//go:generate versionize
|
||||
var VERSION = "1.12.3"
|
||||
var VERSION = "1.13.0"
|
||||
|
||||
func isModuleEnabled(module string, modulesEnabled []string) bool {
|
||||
for _, enabled := range modulesEnabled {
|
||||
|
@ -54,9 +54,18 @@ func makeRouter(config endpoints.ServerConfig) *httprouter.Router {
|
|||
if isModuleEnabled("routes_protocol", whitelist) {
|
||||
r.GET("/routes/protocol/:protocol", endpoints.Endpoint(endpoints.ProtoRoutes))
|
||||
}
|
||||
if isModuleEnabled("routes_peer", whitelist) {
|
||||
r.GET("/routes/peer/:peer", endpoints.Endpoint(endpoints.PeerRoutes))
|
||||
}
|
||||
if isModuleEnabled("routes_table", whitelist) {
|
||||
r.GET("/routes/table/:table", endpoints.Endpoint(endpoints.TableRoutes))
|
||||
}
|
||||
if isModuleEnabled("routes_table_filtered", whitelist) {
|
||||
r.GET("/routes/table/:table/filtered", endpoints.Endpoint(endpoints.TableRoutesFiltered))
|
||||
}
|
||||
if isModuleEnabled("routes_table_peer", whitelist) {
|
||||
r.GET("/routes/table/:table/peer/:peer", endpoints.Endpoint(endpoints.TableAndPeerRoutes))
|
||||
}
|
||||
if isModuleEnabled("routes_count_protocol", whitelist) {
|
||||
r.GET("/routes/count/protocol/:protocol", endpoints.Endpoint(endpoints.ProtoCount))
|
||||
}
|
||||
|
@ -79,12 +88,13 @@ func makeRouter(config endpoints.ServerConfig) *httprouter.Router {
|
|||
r.GET("/route/net/:net", endpoints.Endpoint(endpoints.RouteNet))
|
||||
r.GET("/route/net/:net/table/:table", endpoints.Endpoint(endpoints.RouteNetTable))
|
||||
}
|
||||
if isModuleEnabled("routes_peer", whitelist) {
|
||||
r.GET("/routes/peer", endpoints.Endpoint(endpoints.RoutesPeer))
|
||||
if isModuleEnabled("routes_pipe_filtered_count", whitelist) {
|
||||
r.GET("/routes/pipe/filtered/count", endpoints.Endpoint(endpoints.PipeRoutesFilteredCount))
|
||||
}
|
||||
if isModuleEnabled("routes_dump", whitelist) {
|
||||
r.GET("/routes/dump", endpoints.Endpoint(endpoints.RoutesDump))
|
||||
if isModuleEnabled("routes_pipe_filtered", whitelist) {
|
||||
r.GET("/routes/pipe/filtered", endpoints.Endpoint(endpoints.PipeRoutesFiltered))
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
|
@ -115,8 +125,6 @@ func PrintServiceInfo(conf *Config, birdConf bird.BirdConfig) {
|
|||
for _, m := range conf.Server.ModulesEnabled {
|
||||
log.Println(" -", m)
|
||||
}
|
||||
|
||||
log.Println(" Per Peer Tables:", conf.Parser.PerPeerTables)
|
||||
}
|
||||
|
||||
// MyLogger is our own log.Logger wrapper so we can customize it
|
||||
|
@ -175,9 +183,9 @@ func main() {
|
|||
if conf.Cache.UseRedis {
|
||||
cache, err = bird.NewRedisCache(conf.Cache)
|
||||
if err != nil {
|
||||
log.Fatal("Could not initialize redis cache, falling back to MemoryCache:", err)
|
||||
log.Fatal("Could not initialize redis cache:", err)
|
||||
}
|
||||
} else { // initialze the MemoryCache
|
||||
} else { // initialize the MemoryCache
|
||||
cache, err = bird.NewMemoryCache()
|
||||
if err != nil {
|
||||
log.Fatal("Could not initialize MemoryCache:", err)
|
||||
|
|
|
@ -73,8 +73,6 @@ func Endpoint(wrapped endpoint) httprouter.Handle {
|
|||
res[k] = v
|
||||
}
|
||||
|
||||
js, _ := json.Marshal(res)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
// Check if compression is supported
|
||||
|
@ -83,9 +81,11 @@ func Endpoint(wrapped endpoint) httprouter.Handle {
|
|||
w.Header().Set("Content-Encoding", "gzip")
|
||||
gz := gzip.NewWriter(w)
|
||||
defer gz.Close()
|
||||
gz.Write(js)
|
||||
json := json.NewEncoder(gz)
|
||||
json.Encode(res)
|
||||
} else {
|
||||
w.Write(js) // Fall back to uncompressed response
|
||||
json := json.NewEncoder(w)
|
||||
json.Encode(res) // Fall back to uncompressed response
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ func ProtoRoutes(r *http.Request, ps httprouter.Params) (bird.Parsed, bool) {
|
|||
if err != nil {
|
||||
return bird.Parsed{"error": fmt.Sprintf("%s", err)}, false
|
||||
}
|
||||
|
||||
return bird.RoutesProto(protocol)
|
||||
}
|
||||
|
||||
|
@ -21,6 +22,7 @@ func RoutesFiltered(r *http.Request, ps httprouter.Params) (bird.Parsed, bool) {
|
|||
if err != nil {
|
||||
return bird.Parsed{"error": fmt.Sprintf("%s", err)}, false
|
||||
}
|
||||
|
||||
return bird.RoutesFiltered(protocol)
|
||||
}
|
||||
|
||||
|
@ -29,6 +31,7 @@ func RoutesNoExport(r *http.Request, ps httprouter.Params) (bird.Parsed, bool) {
|
|||
if err != nil {
|
||||
return bird.Parsed{"error": fmt.Sprintf("%s", err)}, false
|
||||
}
|
||||
|
||||
return bird.RoutesNoExport(protocol)
|
||||
}
|
||||
|
||||
|
@ -43,11 +46,40 @@ func RoutesPrefixed(r *http.Request, ps httprouter.Params) (bird.Parsed, bool) {
|
|||
if err != nil {
|
||||
return bird.Parsed{"error": fmt.Sprintf("%s", err)}, false
|
||||
}
|
||||
|
||||
return bird.RoutesPrefixed(prefix)
|
||||
}
|
||||
|
||||
func TableRoutes(r *http.Request, ps httprouter.Params) (bird.Parsed, bool) {
|
||||
return bird.RoutesTable(ps.ByName("table"))
|
||||
table, err := ValidateProtocolParam(ps.ByName("table"))
|
||||
if err != nil {
|
||||
return bird.Parsed{"error": fmt.Sprintf("%s", err)}, false
|
||||
}
|
||||
|
||||
return bird.RoutesTable(table)
|
||||
}
|
||||
|
||||
func TableRoutesFiltered(r *http.Request, ps httprouter.Params) (bird.Parsed, bool) {
|
||||
table, err := ValidateProtocolParam(ps.ByName("table"))
|
||||
if err != nil {
|
||||
return bird.Parsed{"error": fmt.Sprintf("%s", err)}, false
|
||||
}
|
||||
|
||||
return bird.RoutesTableFiltered(table)
|
||||
}
|
||||
|
||||
func TableAndPeerRoutes(r *http.Request, ps httprouter.Params) (bird.Parsed, bool) {
|
||||
table, err := ValidateProtocolParam(ps.ByName("table"))
|
||||
if err != nil {
|
||||
return bird.Parsed{"error": fmt.Sprintf("%s", err)}, false
|
||||
}
|
||||
|
||||
peer, err := ValidatePrefixParam(ps.ByName("peer"))
|
||||
if err != nil {
|
||||
return bird.Parsed{"error": fmt.Sprintf("%s", err)}, false
|
||||
}
|
||||
|
||||
return bird.RoutesTableAndPeer(table, peer)
|
||||
}
|
||||
|
||||
func ProtoCount(r *http.Request, ps httprouter.Params) (bird.Parsed, bool) {
|
||||
|
@ -55,6 +87,7 @@ func ProtoCount(r *http.Request, ps httprouter.Params) (bird.Parsed, bool) {
|
|||
if err != nil {
|
||||
return bird.Parsed{"error": fmt.Sprintf("%s", err)}, false
|
||||
}
|
||||
|
||||
return bird.RoutesProtoCount(protocol)
|
||||
}
|
||||
|
||||
|
@ -67,31 +100,94 @@ func ProtoPrimaryCount(r *http.Request, ps httprouter.Params) (bird.Parsed, bool
|
|||
}
|
||||
|
||||
func TableCount(r *http.Request, ps httprouter.Params) (bird.Parsed, bool) {
|
||||
return bird.RoutesTableCount(ps.ByName("table"))
|
||||
}
|
||||
|
||||
func RouteNet(r *http.Request, ps httprouter.Params) (bird.Parsed, bool) {
|
||||
return bird.RoutesLookupTable(ps.ByName("net"), "master")
|
||||
}
|
||||
|
||||
func RouteNetTable(r *http.Request, ps httprouter.Params) (bird.Parsed, bool) {
|
||||
return bird.RoutesLookupTable(ps.ByName("net"), ps.ByName("table"))
|
||||
}
|
||||
|
||||
func RoutesPeer(r *http.Request, ps httprouter.Params) (bird.Parsed, bool) {
|
||||
qs := r.URL.Query()
|
||||
peerl := qs["peer"]
|
||||
if len(peerl) != 1 {
|
||||
return bird.Parsed{"error": "need a peer as single query parameter"}, false
|
||||
}
|
||||
|
||||
peer, err := ValidateProtocolParam(peerl[0])
|
||||
table, err := ValidateProtocolParam(ps.ByName("table"))
|
||||
if err != nil {
|
||||
return bird.Parsed{"error": fmt.Sprintf("%s", err)}, false
|
||||
}
|
||||
return bird.RoutesPeer(peer)
|
||||
|
||||
return bird.RoutesTableCount(table)
|
||||
}
|
||||
|
||||
func RoutesDump(r *http.Request, ps httprouter.Params) (bird.Parsed, bool) {
|
||||
return bird.RoutesDump()
|
||||
func RouteNet(r *http.Request, ps httprouter.Params) (bird.Parsed, bool) {
|
||||
net, err := ValidatePrefixParam(ps.ByName("net"))
|
||||
if err != nil {
|
||||
return bird.Parsed{"error": fmt.Sprintf("%s", err)}, false
|
||||
}
|
||||
|
||||
return bird.RoutesLookupTable(net, "master")
|
||||
}
|
||||
|
||||
func RouteNetTable(r *http.Request, ps httprouter.Params) (bird.Parsed, bool) {
|
||||
net, err := ValidatePrefixParam(ps.ByName("net"))
|
||||
if err != nil {
|
||||
return bird.Parsed{"error": fmt.Sprintf("%s", err)}, false
|
||||
}
|
||||
|
||||
table, err := ValidateProtocolParam(ps.ByName("table"))
|
||||
if err != nil {
|
||||
return bird.Parsed{"error": fmt.Sprintf("%s", err)}, false
|
||||
}
|
||||
|
||||
return bird.RoutesLookupTable(net, table)
|
||||
}
|
||||
|
||||
func PipeRoutesFiltered(r *http.Request, ps httprouter.Params) (bird.Parsed, bool) {
|
||||
qs := r.URL.Query()
|
||||
|
||||
if len(qs["table"]) != 1 {
|
||||
return bird.Parsed{"error": "need a table as single query parameter"}, false
|
||||
}
|
||||
table, err := ValidateProtocolParam(qs["table"][0])
|
||||
if err != nil {
|
||||
return bird.Parsed{"error": fmt.Sprintf("%s", err)}, false
|
||||
}
|
||||
|
||||
if len(qs["pipe"]) != 1 {
|
||||
return bird.Parsed{"error": "need a pipe as single query parameter"}, false
|
||||
}
|
||||
pipe, err := ValidateProtocolParam(qs["pipe"][0])
|
||||
if err != nil {
|
||||
return bird.Parsed{"error": fmt.Sprintf("%s", err)}, false
|
||||
}
|
||||
|
||||
return bird.PipeRoutesFiltered(pipe, table)
|
||||
}
|
||||
|
||||
func PipeRoutesFilteredCount(r *http.Request, ps httprouter.Params) (bird.Parsed, bool) {
|
||||
qs := r.URL.Query()
|
||||
|
||||
if len(qs["table"]) != 1 {
|
||||
return bird.Parsed{"error": "need a table as single query parameter"}, false
|
||||
}
|
||||
table, err := ValidateProtocolParam(qs["table"][0])
|
||||
if err != nil {
|
||||
return bird.Parsed{"error": fmt.Sprintf("%s", err)}, false
|
||||
}
|
||||
|
||||
if len(qs["pipe"]) != 1 {
|
||||
return bird.Parsed{"error": "need a pipe as single query parameter"}, false
|
||||
}
|
||||
pipe, err := ValidateProtocolParam(qs["pipe"][0])
|
||||
if err != nil {
|
||||
return bird.Parsed{"error": fmt.Sprintf("%s", err)}, false
|
||||
}
|
||||
|
||||
if len(qs["address"]) != 1 {
|
||||
return bird.Parsed{"error": "need a address as single query parameter"}, false
|
||||
}
|
||||
address, err := ValidatePrefixParam(qs["address"][0])
|
||||
if err != nil {
|
||||
return bird.Parsed{"error": fmt.Sprintf("%s", err)}, false
|
||||
}
|
||||
|
||||
return bird.PipeRoutesFilteredCount(pipe, table, address)
|
||||
}
|
||||
|
||||
func PeerRoutes(r *http.Request, ps httprouter.Params) (bird.Parsed, bool) {
|
||||
peer, err := ValidatePrefixParam(ps.ByName("peer"))
|
||||
if err != nil {
|
||||
return bird.Parsed{"error": fmt.Sprintf("%s", err)}, false
|
||||
}
|
||||
|
||||
return bird.RoutesPeer(peer)
|
||||
}
|
||||
|
|
15
etc/birdwatcher/birdwatcher.conf
Normal file → Executable file
15
etc/birdwatcher/birdwatcher.conf
Normal file → Executable file
|
@ -15,7 +15,10 @@ allow_from = []
|
|||
# protocols
|
||||
# protocols_bgp
|
||||
# routes_protocol
|
||||
# routes_peer
|
||||
# routes_table
|
||||
# routes_table_filtered
|
||||
# routes_table_peer
|
||||
# routes_count_protocol
|
||||
# routes_count_table
|
||||
# routes_count_primary
|
||||
|
@ -23,8 +26,8 @@ allow_from = []
|
|||
# routes_prefixed
|
||||
# routes_noexport
|
||||
# route_net
|
||||
## high-level modules (aggregated data from multiple birdc invocations)
|
||||
# routes_dump
|
||||
# routes_pipe_filtered_count
|
||||
# routes_pipe_filtered
|
||||
# routes_peer
|
||||
|
||||
|
||||
|
@ -33,8 +36,14 @@ modules_enabled = ["status",
|
|||
"protocols_bgp",
|
||||
"routes_protocol",
|
||||
"routes_peer",
|
||||
"routes_table",
|
||||
"routes_table_filtered",
|
||||
"routes_table_peer",
|
||||
"routes_filtered",
|
||||
"routes_prefixed",
|
||||
"routes_dump"
|
||||
"routes_noexport",
|
||||
"routes_pipe_filtered_count",
|
||||
"routes_pipe_filtered"
|
||||
]
|
||||
|
||||
[status]
|
||||
|
|
Loading…
Add table
Reference in a new issue