1
0
Fork 0
mirror of https://github.com/alice-lg/birdwatcher.git synced 2025-03-09 00:00:05 +01:00
birdwatcher/bird/bird.go

220 lines
4.4 KiB
Go
Raw Permalink Normal View History

2016-11-10 14:16:44 +01:00
package bird
import (
2016-11-10 15:11:32 +01:00
"os/exec"
"strings"
2016-11-11 17:47:51 +01:00
"sync"
"time"
2016-11-10 14:16:44 +01:00
)
var ClientConf BirdConfig
var StatusConf StatusConfig
2016-12-13 11:01:28 +01:00
var RateLimitConf struct {
2016-12-13 11:58:08 +01:00
sync.RWMutex
2016-12-13 11:01:28 +01:00
Conf RateLimitConfig
}
2016-11-25 15:50:59 +01:00
2016-11-11 17:47:51 +01:00
var Cache = struct {
sync.RWMutex
m map[string]Parsed
2016-11-11 17:33:33 +01:00
}{m: make(map[string]Parsed)}
func fromCache(key string) (Parsed, bool) {
2016-11-11 17:47:51 +01:00
Cache.RLock()
val, ok := Cache.m[key]
Cache.RUnlock()
2016-12-21 12:16:29 +01:00
if !ok {
return nil, false
}
ttl, correct := val["ttl"].(time.Time)
if !correct || ttl.Before(time.Now()) {
return nil, false
}
2016-11-11 17:47:51 +01:00
return val, ok
2016-11-11 17:33:33 +01:00
}
func toCache(key string, val Parsed) {
2016-11-11 17:47:51 +01:00
val["ttl"] = time.Now().Add(5 * time.Minute)
Cache.Lock()
Cache.m[key] = val
Cache.Unlock()
2016-11-11 17:33:33 +01:00
}
2016-11-10 14:16:44 +01:00
func Run(args string) ([]byte, error) {
2016-11-10 16:06:38 +01:00
args = "show " + args
2016-11-10 15:11:32 +01:00
argsList := strings.Split(args, " ")
return exec.Command(ClientConf.BirdCmd, argsList...).Output()
2016-11-10 14:16:44 +01:00
}
2016-11-25 15:50:59 +01:00
func InstallRateLimitReset() {
go func() {
c := time.Tick(time.Second)
for _ = range c {
2016-12-13 11:01:28 +01:00
RateLimitConf.Lock()
2016-12-13 14:04:14 +01:00
RateLimitConf.Conf.Reqs = RateLimitConf.Conf.Max
2016-12-13 11:01:28 +01:00
RateLimitConf.Unlock()
2016-11-25 15:50:59 +01:00
}
}()
}
func checkRateLimit() bool {
2016-12-13 11:58:08 +01:00
RateLimitConf.RLock()
check := !RateLimitConf.Conf.Enabled
RateLimitConf.RUnlock()
if check {
2016-12-13 10:49:18 +01:00
return true
}
2016-12-13 11:58:08 +01:00
RateLimitConf.RLock()
2016-12-13 14:04:14 +01:00
check = RateLimitConf.Conf.Reqs < 1
2016-12-13 11:58:08 +01:00
RateLimitConf.RUnlock()
if check {
2016-11-25 15:50:59 +01:00
return false
}
2016-12-13 11:01:28 +01:00
RateLimitConf.Lock()
2016-12-13 14:04:14 +01:00
RateLimitConf.Conf.Reqs -= 1
2016-12-13 11:01:28 +01:00
RateLimitConf.Unlock()
2016-11-25 15:50:59 +01:00
return true
}
2016-11-11 17:33:33 +01:00
func RunAndParse(cmd string, parser func([]byte) Parsed) (Parsed, bool) {
2016-11-11 17:47:51 +01:00
if val, ok := fromCache(cmd); ok {
return val, true
}
2016-11-11 17:33:33 +01:00
2016-11-25 15:50:59 +01:00
if !checkRateLimit() {
return nil, false
}
2016-11-10 15:11:32 +01:00
out, err := Run(cmd)
2016-11-10 14:16:44 +01:00
2016-11-10 15:11:32 +01:00
if err != nil {
// ignore errors for now
2016-11-11 17:33:33 +01:00
return Parsed{}, false
2016-11-10 15:11:32 +01:00
}
2016-11-10 14:16:44 +01:00
2016-11-11 17:33:33 +01:00
parsed := parser(out)
2016-11-11 17:47:51 +01:00
toCache(cmd, parsed)
return parsed, false
2016-11-10 14:16:44 +01:00
}
2016-11-11 17:33:33 +01:00
func Status() (Parsed, bool) {
birdStatus, ok := RunAndParse("status", parseStatus)
if birdStatus == nil {
return birdStatus, ok
}
2016-12-05 14:54:13 +01:00
status := birdStatus["status"].(Parsed)
// Last Reconfig Timestamp source:
var lastReconfig string
switch StatusConf.ReconfigTimestampSource {
case "bird":
2016-12-05 14:33:21 +01:00
lastReconfig = status["last_reconfig"].(string)
break
case "config_modified":
lastReconfig = lastReconfigTimestampFromFileStat(
ClientConf.ConfigFilename,
)
case "config_regex":
lastReconfig = lastReconfigTimestampFromFileContent(
ClientConf.ConfigFilename,
StatusConf.ReconfigTimestampMatch,
)
}
2016-12-05 14:33:21 +01:00
status["last_reconfig"] = lastReconfig
// Filter fields
2016-12-02 17:11:57 +01:00
for _, field := range StatusConf.FilterFields {
2016-12-05 14:33:21 +01:00
status[field] = nil
2016-12-02 17:11:57 +01:00
}
2016-12-05 14:33:21 +01:00
birdStatus["status"] = status
return birdStatus, ok
2016-11-10 14:16:44 +01:00
}
2016-11-11 17:33:33 +01:00
func Protocols() (Parsed, bool) {
2016-11-10 15:11:32 +01:00
return RunAndParse("protocols all", parseProtocols)
2016-11-10 14:16:44 +01:00
}
2016-11-11 17:33:33 +01:00
func ProtocolsBgp() (Parsed, bool) {
p, from_cache := Protocols()
if p == nil {
return p, from_cache
}
2016-11-11 17:47:51 +01:00
protocols := p["protocols"].([]string)
2016-11-10 18:43:29 +01:00
2016-11-11 13:32:27 +01:00
bgpProto := Parsed{}
2016-11-10 18:43:29 +01:00
2016-11-11 13:32:27 +01:00
for _, v := range protocols {
if strings.Contains(v, " BGP ") {
key := strings.Split(v, " ")[0]
bgpProto[key] = parseBgp(v)
}
}
2016-11-10 18:43:29 +01:00
2017-02-16 17:25:35 +01:00
return Parsed{"protocols": bgpProto, "ttl": p["ttl"]}, from_cache
2016-11-10 18:43:29 +01:00
}
2016-11-11 17:33:33 +01:00
func Symbols() (Parsed, bool) {
2016-11-10 15:11:32 +01:00
return RunAndParse("symbols", parseSymbols)
2016-11-10 14:16:44 +01:00
}
2016-12-08 11:09:25 +01:00
func RoutesPrefixed(prefix string) (Parsed, bool) {
return RunAndParse("route all '"+prefix+"'", parseRoutes)
}
2016-11-11 17:33:33 +01:00
func RoutesProto(protocol string) (Parsed, bool) {
2016-11-24 17:59:19 +01:00
return RunAndParse("route protocol '"+protocol+"' all",
2016-11-10 15:11:32 +01:00
parseRoutes)
2016-11-10 14:16:44 +01:00
}
2016-11-11 17:33:33 +01:00
func RoutesProtoCount(protocol string) (Parsed, bool) {
2016-11-24 17:59:19 +01:00
return RunAndParse("route protocol '"+protocol+"' count",
2016-11-10 15:11:32 +01:00
parseRoutesCount)
2016-11-10 14:16:44 +01:00
}
2016-12-06 17:20:27 +01:00
func RoutesFiltered(protocol string) (Parsed, bool) {
2017-02-22 16:09:54 +01:00
return RunAndParse("route filtered protocol '"+protocol+"' all", parseRoutes)
2016-12-06 17:20:27 +01:00
}
2016-11-11 17:33:33 +01:00
func RoutesExport(protocol string) (Parsed, bool) {
2016-11-24 17:59:19 +01:00
return RunAndParse("route export '"+protocol+"' all",
2016-11-10 15:11:32 +01:00
parseRoutes)
2016-11-10 14:16:44 +01:00
}
2016-11-11 17:33:33 +01:00
func RoutesExportCount(protocol string) (Parsed, bool) {
2016-11-24 17:59:19 +01:00
return RunAndParse("route export '"+protocol+"' count",
2016-11-10 15:11:32 +01:00
parseRoutesCount)
2016-11-10 14:16:44 +01:00
}
2016-11-11 17:33:33 +01:00
func RoutesTable(table string) (Parsed, bool) {
2016-11-24 17:59:19 +01:00
return RunAndParse("route table '"+table+"' all",
2016-11-10 15:11:32 +01:00
parseRoutes)
2016-11-10 14:16:44 +01:00
}
2016-11-11 17:33:33 +01:00
func RoutesTableCount(table string) (Parsed, bool) {
2016-11-24 17:59:19 +01:00
return RunAndParse("route table '"+table+"' count",
2016-11-10 15:11:32 +01:00
parseRoutesCount)
2016-11-10 14:16:44 +01:00
}
2016-11-11 17:33:33 +01:00
func RoutesLookupTable(net string, table string) (Parsed, bool) {
2016-11-24 17:59:19 +01:00
return RunAndParse("route for '"+net+"' table '"+table+"' all",
2016-11-10 15:11:32 +01:00
parseRoutes)
2016-11-10 14:16:44 +01:00
}
2016-11-11 17:33:33 +01:00
func RoutesLookupProtocol(net string, protocol string) (Parsed, bool) {
2016-11-24 17:59:19 +01:00
return RunAndParse("route for '"+net+"' protocol '"+protocol+"' all",
2016-11-10 15:11:32 +01:00
parseRoutes)
2016-11-10 14:16:44 +01:00
}
2017-02-15 12:20:55 +01:00
func RoutesPeer(peer string) (Parsed, bool) {
return RunAndParse("route export '"+peer+"'", parseRoutes)
}