mirror of
https://github.com/alice-lg/birdwatcher.git
synced 2025-03-09 00:00:05 +01:00
refactoring, channel support for show protocols, routees filtered by ip version
This commit is contained in:
parent
654e131a75
commit
d903f1286b
4 changed files with 320 additions and 183 deletions
56
bird/bird.go
56
bird/bird.go
|
@ -1,6 +1,7 @@
|
|||
package bird
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
|
@ -11,6 +12,7 @@ import (
|
|||
|
||||
var ClientConf BirdConfig
|
||||
var StatusConf StatusConfig
|
||||
var IPVersion = "4"
|
||||
var RateLimitConf struct {
|
||||
sync.RWMutex
|
||||
Conf RateLimitConfig
|
||||
|
@ -175,26 +177,28 @@ func Symbols() (Parsed, bool) {
|
|||
}
|
||||
|
||||
func RoutesPrefixed(prefix string) (Parsed, bool) {
|
||||
return RunAndParse("route all "+prefix, parseRoutes)
|
||||
cmd := fmt.Sprintf("route all where net.type = NET_IP%s", IPVersion)
|
||||
return RunAndParse(cmd, parseRoutes)
|
||||
}
|
||||
|
||||
func RoutesProto(protocol string) (Parsed, bool) {
|
||||
return RunAndParse("route protocol '"+protocol+"' all",
|
||||
parseRoutes)
|
||||
cmd := fmt.Sprintf("route all protocol %s where net.type = NET_IP%s", protocol, IPVersion)
|
||||
return RunAndParse(cmd, parseRoutes)
|
||||
}
|
||||
|
||||
func RoutesProtoCount(protocol string) (Parsed, bool) {
|
||||
return RunAndParse("route protocol '"+protocol+"' count",
|
||||
parseRoutesCount)
|
||||
cmd := fmt.Sprintf("route all protocol %s where net.type = NET_IP%s count", protocol, IPVersion)
|
||||
return RunAndParse(cmd, parseRoutes)
|
||||
}
|
||||
|
||||
func RoutesFiltered(protocol string) (Parsed, bool) {
|
||||
return RunAndParse("route filtered protocol '"+protocol+"' all", parseRoutes)
|
||||
cmd := fmt.Sprintf("route all filtered %s where net.type = NET_IP%s", protocol, IPVersion)
|
||||
return RunAndParse(cmd, parseRoutes)
|
||||
}
|
||||
|
||||
func RoutesExport(protocol string) (Parsed, bool) {
|
||||
return RunAndParse("route export '"+protocol+"' all",
|
||||
parseRoutes)
|
||||
cmd := fmt.Sprintf("route all export %s where net.type = NET_IP%s", protocol, IPVersion)
|
||||
return RunAndParse(cmd, parseRoutes)
|
||||
}
|
||||
|
||||
func RoutesNoExport(protocol string) (Parsed, bool) {
|
||||
|
@ -209,49 +213,47 @@ func RoutesNoExport(protocol string) (Parsed, bool) {
|
|||
protocol[len(ParserConf.PeerProtocolPrefix):]
|
||||
}
|
||||
|
||||
return RunAndParse("route noexport '"+protocol+"' all",
|
||||
parseRoutes)
|
||||
cmd := fmt.Sprintf("route all noexport %s where net.type = NET_IP%s", protocol, IPVersion)
|
||||
return RunAndParse(cmd, parseRoutes)
|
||||
}
|
||||
|
||||
func RoutesExportCount(protocol string) (Parsed, bool) {
|
||||
return RunAndParse("route export '"+protocol+"' count",
|
||||
parseRoutesCount)
|
||||
cmd := fmt.Sprintf("route all export %s where net.type = NET_IP%s count", protocol, IPVersion)
|
||||
return RunAndParse(cmd, parseRoutesCount)
|
||||
}
|
||||
|
||||
func RoutesTable(table string) (Parsed, bool) {
|
||||
return RunAndParse("route table '"+table+"' all",
|
||||
parseRoutes)
|
||||
return RunAndParse("route table '"+table+"' all", parseRoutes)
|
||||
}
|
||||
|
||||
func RoutesTableCount(table string) (Parsed, bool) {
|
||||
return RunAndParse("route table '"+table+"' count",
|
||||
parseRoutesCount)
|
||||
return RunAndParse("route table '"+table+"' count", parseRoutesCount)
|
||||
}
|
||||
|
||||
func RoutesLookupTable(net string, table string) (Parsed, bool) {
|
||||
return RunAndParse("route for '"+net+"' table '"+table+"' all",
|
||||
parseRoutes)
|
||||
return RunAndParse("route for '"+net+"' table '"+table+"' all", parseRoutes)
|
||||
}
|
||||
|
||||
func RoutesLookupProtocol(net string, protocol string) (Parsed, bool) {
|
||||
return RunAndParse("route for '"+net+"' protocol '"+protocol+"' all",
|
||||
parseRoutes)
|
||||
return RunAndParse("route for '"+net+"' protocol '"+protocol+"' all", parseRoutes)
|
||||
}
|
||||
|
||||
func RoutesPeer(peer string) (Parsed, bool) {
|
||||
return RunAndParse("route export '"+peer+"'", parseRoutes)
|
||||
cmd := fmt.Sprintf("route export %s where net.type = NET_IP%s", peer, IPVersion)
|
||||
return RunAndParse(cmd, parseRoutes)
|
||||
}
|
||||
|
||||
func RoutesDump() (Parsed, bool) {
|
||||
if ParserConf.PerPeerTables {
|
||||
return RoutesDumpPerPeerTable()
|
||||
}
|
||||
|
||||
return RoutesDumpSingleTable()
|
||||
}
|
||||
|
||||
func RoutesDumpSingleTable() (Parsed, bool) {
|
||||
importedRes, cached := RunAndParse("route all", parseRoutes)
|
||||
filteredRes, _ := RunAndParse("route filtered all", parseRoutes)
|
||||
importedRes, cached := RunAndParse(fmt.Sprintf("route all where net.type = NET_IP%s", IPVersion), parseRoutes)
|
||||
filteredRes, _ := RunAndParse(fmt.Sprintf("route all filtered where net.type = NET_IP%s", IPVersion), parseRoutes)
|
||||
|
||||
imported := importedRes["routes"]
|
||||
filtered := filteredRes["routes"]
|
||||
|
@ -260,11 +262,12 @@ func RoutesDumpSingleTable() (Parsed, bool) {
|
|||
"imported": imported,
|
||||
"filtered": filtered,
|
||||
}
|
||||
|
||||
return result, cached
|
||||
}
|
||||
|
||||
func RoutesDumpPerPeerTable() (Parsed, bool) {
|
||||
importedRes, cached := RunAndParse("route all", parseRoutes)
|
||||
importedRes, cached := RunAndParse("route all where net.type = NET_IP"+IPVersion, parseRoutes)
|
||||
imported := importedRes["routes"]
|
||||
filtered := []Parsed{}
|
||||
|
||||
|
@ -286,9 +289,7 @@ func RoutesDumpPerPeerTable() (Parsed, bool) {
|
|||
continue // nothing to do here.
|
||||
}
|
||||
// Lookup filtered routes
|
||||
pfilteredRes, _ := RunAndParse(
|
||||
"route filtered protocol '"+protocol+"' all",
|
||||
parseRoutes)
|
||||
pfilteredRes, _ := RoutesFiltered(protocol)
|
||||
|
||||
pfiltered, ok := pfilteredRes["routes"].([]Parsed)
|
||||
if !ok {
|
||||
|
@ -302,5 +303,6 @@ func RoutesDumpPerPeerTable() (Parsed, bool) {
|
|||
"imported": imported,
|
||||
"filtered": filtered,
|
||||
}
|
||||
|
||||
return result, cached
|
||||
}
|
||||
|
|
|
@ -16,11 +16,10 @@ 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"`
|
||||
PerPeerTables bool `toml:"per_peer_tables"`
|
||||
PeerProtocolPrefix string `toml:"peer_protocol_prefix"`
|
||||
PipeProtocolPrefix string `toml:"pipe_protocol_prefix"`
|
||||
}
|
||||
|
||||
type RateLimitConfig struct {
|
||||
|
|
436
bird/parser.go
436
bird/parser.go
|
@ -1,21 +1,91 @@
|
|||
package bird
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var ParserConf ParserConfig
|
||||
var (
|
||||
ParserConf ParserConfig
|
||||
regex struct {
|
||||
lineSeperator *regexp.Regexp
|
||||
status struct {
|
||||
startLine *regexp.Regexp
|
||||
routerID *regexp.Regexp
|
||||
currentServer *regexp.Regexp
|
||||
lastReboot *regexp.Regexp
|
||||
lastReconfig *regexp.Regexp
|
||||
}
|
||||
bgp struct {
|
||||
channel *regexp.Regexp
|
||||
protocol *regexp.Regexp
|
||||
numericValue *regexp.Regexp
|
||||
routes *regexp.Regexp
|
||||
stringValue *regexp.Regexp
|
||||
importUpdates *regexp.Regexp
|
||||
importWithdraws *regexp.Regexp
|
||||
exportUpdates *regexp.Regexp
|
||||
exportWithdraws *regexp.Regexp
|
||||
}
|
||||
symbols struct {
|
||||
keyRx *regexp.Regexp
|
||||
}
|
||||
routeCount struct {
|
||||
countRx *regexp.Regexp
|
||||
}
|
||||
routes struct {
|
||||
startDefinition *regexp.Regexp
|
||||
second *regexp.Regexp
|
||||
routeType *regexp.Regexp
|
||||
bgp *regexp.Regexp
|
||||
community *regexp.Regexp
|
||||
largeCommunity *regexp.Regexp
|
||||
origin *regexp.Regexp
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
type Parsed map[string]interface{}
|
||||
|
||||
func init() {
|
||||
regex.status.startLine = regexp.MustCompile(`^BIRD\s([0-9\.]+)\s*$`)
|
||||
regex.status.routerID = regexp.MustCompile(`^Router\sID\sis\s([0-9\.]+)\s*$`)
|
||||
regex.status.currentServer = regexp.MustCompile(`^Current\sserver\stime\sis\s([0-9\-]+\s[0-9\:]+)\s*$`)
|
||||
regex.status.lastReboot = regexp.MustCompile(`^Last\sreboot\son\s([0-9\-]+\s[0-9\:]+)\s*$`)
|
||||
regex.status.lastReconfig = regexp.MustCompile(`^Last\sreconfiguration\son\s([0-9\-]+\s[0-9\:]+)\s*$`)
|
||||
|
||||
regex.symbols.keyRx = regexp.MustCompile(`^([^\s]+)\s+(.+)\s*$`)
|
||||
|
||||
regex.routeCount.countRx = regexp.MustCompile(`^(\d+)\s+of\s+(\d+)\s+routes.*$`)
|
||||
|
||||
regex.bgp.channel = regexp.MustCompile("Channel ipv([46])")
|
||||
regex.bgp.protocol = regexp.MustCompile(`^([\w\.:]+)\s+BGP\s+(\w+)\s+(\w+)\s+([0-9]{4}-[0-9]{2}-[0-9]{2}\s+[0-9]{2}:[0-9]{2}:[0-9]{2})\s*(\w+)?.*$`)
|
||||
regex.bgp.numericValue = regexp.MustCompile(`^\s+([^:]+):\s+([\d]+)\s*$`)
|
||||
regex.bgp.routes = regexp.MustCompile(`^\s+Routes:\s+(.*)`)
|
||||
regex.bgp.stringValue = regexp.MustCompile(`^\s+([^:]+):\s+(.+)\s*$`)
|
||||
regex.bgp.importUpdates = regexp.MustCompile(`^\s+Import updates:\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s*$`)
|
||||
regex.bgp.importWithdraws = regexp.MustCompile(`^\s+Import withdraws:\s+(\d+)\s+(\d+)\s+\-\-\-\s+(\d+)\s+(\d+)\s*$`)
|
||||
regex.bgp.exportUpdates = regexp.MustCompile(`^\s+Export updates:\s+(\d+)\s+(\d+)\s+(\d+)\s+\-\-\-\s+(\d+)\s*$`)
|
||||
regex.bgp.exportWithdraws = regexp.MustCompile(`^\s+Export withdraws:\s+(\d+)(\s+\-\-\-){2}\s+(\d+)\s*$`)
|
||||
|
||||
regex.routes.startDefinition = regexp.MustCompile(`^([0-9a-f\.\:\/]+)\s+via\s+([0-9a-f\.\:]+)\s+on\s+([\w\.]+)\s+\[([\w\.:]+)\s+([0-9\-\:\s]+)(?:\s+from\s+([0-9a-f\.\:\/]+)){0,1}\]\s+(?:(\*)\s+){0,1}\((\d+)(?:\/\d+){0,1}\).*`)
|
||||
regex.routes.second = regexp.MustCompile(`^\s+via\s+([0-9a-f\.\:]+)\s+on\s+([\w\.]+)\s+\[([\w\.:]+)\s+([0-9\-\:\s]+)(?:\s+from\s+([0-9a-f\.\:\/]+)){0,1}\]\s+(?:(\*)\s+){0,1}\((\d+)(?:\/\d+){0,1}\).*$`)
|
||||
regex.routes.routeType = regexp.MustCompile(`^\s+Type:\s+(.*)\s*$`)
|
||||
regex.routes.bgp = regexp.MustCompile(`^\s+BGP.(\w+):\s+(.+)\s*$`)
|
||||
regex.routes.community = regexp.MustCompile(`^\((\d+),\s*(\d+)\)`)
|
||||
regex.routes.largeCommunity = regexp.MustCompile(`^\((\d+),\s*(\d+),\s*(\d+)\)`)
|
||||
regex.routes.origin = regexp.MustCompile(`\([^\(]*\)\s*`)
|
||||
}
|
||||
|
||||
func dirtyContains(l []string, e string) bool {
|
||||
for _, c := range l {
|
||||
if c == e {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -24,8 +94,16 @@ func emptyLine(line string) bool {
|
|||
}
|
||||
|
||||
func getLinesUnfiltered(input string) []string {
|
||||
line_sep := regexp.MustCompile(`((\r?\n)|(\r\n?))`)
|
||||
return line_sep.Split(input, -1)
|
||||
lines := make([]string, 0)
|
||||
|
||||
reader := strings.NewReader(input)
|
||||
scanner := bufio.NewScanner(reader)
|
||||
|
||||
for scanner.Scan() {
|
||||
lines = append(lines, scanner.Text())
|
||||
}
|
||||
|
||||
return lines
|
||||
}
|
||||
|
||||
func getLinesFromString(input string) []string {
|
||||
|
@ -47,37 +125,30 @@ func getLines(input []byte) []string {
|
|||
}
|
||||
|
||||
func specialLine(line string) bool {
|
||||
return (strings.HasPrefix(line, "BIRD") ||
|
||||
strings.HasPrefix(line, "Access restricted"))
|
||||
return (strings.HasPrefix(line, "BIRD") || strings.HasPrefix(line, "Access restricted"))
|
||||
}
|
||||
|
||||
func parseStatus(input []byte) Parsed {
|
||||
res := Parsed{}
|
||||
lines := getLines(input)
|
||||
|
||||
start_line_rx := regexp.MustCompile(`^BIRD\s([0-9\.]+)\s*$`)
|
||||
router_id_rx := regexp.MustCompile(`^Router\sID\sis\s([0-9\.]+)\s*$`)
|
||||
current_server_rx := regexp.MustCompile(`^Current\sserver\stime\sis\s([0-9\-]+\s[0-9\:]+)\s*$`)
|
||||
last_reboot_rx := regexp.MustCompile(`^Last\sreboot\son\s([0-9\-]+\s[0-9\:]+)\s*$`)
|
||||
last_reconfig_rx := regexp.MustCompile(`^Last\sreconfiguration\son\s([0-9\-]+\s[0-9\:]+)\s*$`)
|
||||
|
||||
for _, line := range lines {
|
||||
if start_line_rx.MatchString(line) {
|
||||
res["version"] = start_line_rx.FindStringSubmatch(line)[1]
|
||||
} else if router_id_rx.MatchString(line) {
|
||||
res["router_id"] = router_id_rx.FindStringSubmatch(line)[1]
|
||||
} else if current_server_rx.MatchString(line) {
|
||||
res["current_server"] = current_server_rx.FindStringSubmatch(line)[1]
|
||||
} else if last_reboot_rx.MatchString(line) {
|
||||
res["last_reboot"] = last_reboot_rx.FindStringSubmatch(line)[1]
|
||||
} else if last_reconfig_rx.MatchString(line) {
|
||||
res["last_reconfig"] = last_reconfig_rx.FindStringSubmatch(line)[1]
|
||||
if regex.status.startLine.MatchString(line) {
|
||||
res["version"] = regex.status.startLine.FindStringSubmatch(line)[1]
|
||||
} else if regex.status.routerID.MatchString(line) {
|
||||
res["router_id"] = regex.status.routerID.FindStringSubmatch(line)[1]
|
||||
} else if regex.status.currentServer.MatchString(line) {
|
||||
res["current_server"] = regex.status.currentServer.FindStringSubmatch(line)[1]
|
||||
} else if regex.status.lastReboot.MatchString(line) {
|
||||
res["last_reboot"] = regex.status.lastReboot.FindStringSubmatch(line)[1]
|
||||
} else if regex.status.lastReconfig.MatchString(line) {
|
||||
res["last_reconfig"] = regex.status.lastReconfig.FindStringSubmatch(line)[1]
|
||||
} else {
|
||||
res["message"] = line
|
||||
}
|
||||
}
|
||||
|
||||
for k, _ := range res {
|
||||
for k := range res {
|
||||
if dirtyContains(ParserConf.FilterFields, k) {
|
||||
res[k] = nil
|
||||
}
|
||||
|
@ -111,14 +182,13 @@ func parseSymbols(input []byte) Parsed {
|
|||
res := Parsed{}
|
||||
lines := getLines(input)
|
||||
|
||||
key_rx := regexp.MustCompile(`^([^\s]+)\s+(.+)\s*$`)
|
||||
for _, line := range lines {
|
||||
if specialLine(line) {
|
||||
continue
|
||||
}
|
||||
|
||||
if key_rx.MatchString(line) {
|
||||
groups := key_rx.FindStringSubmatch(line)
|
||||
if regex.symbols.keyRx.MatchString(line) {
|
||||
groups := regex.symbols.keyRx.FindStringSubmatch(line)
|
||||
res[groups[2]] = groups[1]
|
||||
}
|
||||
}
|
||||
|
@ -136,7 +206,7 @@ func mainRouteDetail(groups []string, route Parsed) Parsed {
|
|||
route["primary"] = groups[7] == "*"
|
||||
route["metric"] = parseInt(groups[8])
|
||||
|
||||
for k, _ := range route {
|
||||
for k := range route {
|
||||
if dirtyContains(ParserConf.FilterFields, k) {
|
||||
route[k] = nil
|
||||
}
|
||||
|
@ -150,27 +220,20 @@ func parseRoutes(input []byte) Parsed {
|
|||
lines := getLines(input)
|
||||
|
||||
routes := []Parsed{}
|
||||
|
||||
route := Parsed{}
|
||||
start_def_rx := regexp.MustCompile(`^([0-9a-f\.\:\/]+)\s+via\s+([0-9a-f\.\:]+)\s+on\s+([\w\.]+)\s+\[([\w\.:]+)\s+([0-9\-\:\s]+)(?:\s+from\s+([0-9a-f\.\:\/]+)){0,1}\]\s+(?:(\*)\s+){0,1}\((\d+)(?:\/\d+){0,1}\).*`)
|
||||
second_rx := regexp.MustCompile(`^\s+via\s+([0-9a-f\.\:]+)\s+on\s+([\w\.]+)\s+\[([\w\.:]+)\s+([0-9\-\:\s]+)(?:\s+from\s+([0-9a-f\.\:\/]+)){0,1}\]\s+(?:(\*)\s+){0,1}\((\d+)(?:\/\d+){0,1}\).*$`)
|
||||
type_rx := regexp.MustCompile(`^\s+Type:\s+(.*)\s*$`)
|
||||
bgp_rx := regexp.MustCompile(`^\s+BGP.(\w+):\s+(.+)\s*$`)
|
||||
community_rx := regexp.MustCompile(`^\((\d+),\s*(\d+)\)`)
|
||||
large_community_rx := regexp.MustCompile(`^\((\d+),\s*(\d+),\s*(\d+)\)`)
|
||||
paren_rx := regexp.MustCompile(`\([^\(]*\)\s*`)
|
||||
|
||||
for _, line := range lines {
|
||||
if specialLine(line) || (len(route) == 0 && emptyLine(line)) {
|
||||
continue
|
||||
}
|
||||
|
||||
if start_def_rx.MatchString(line) {
|
||||
if regex.routes.startDefinition.MatchString(line) {
|
||||
if len(route) > 0 {
|
||||
routes = append(routes, route)
|
||||
route = Parsed{}
|
||||
}
|
||||
route = mainRouteDetail(start_def_rx.FindStringSubmatch(line), route)
|
||||
} else if second_rx.MatchString(line) {
|
||||
route = mainRouteDetail(regex.routes.startDefinition.FindStringSubmatch(line), route)
|
||||
} else if regex.routes.second.MatchString(line) {
|
||||
routes = append(routes, route)
|
||||
var network string
|
||||
if tmp, ok := route["network"]; ok {
|
||||
|
@ -184,16 +247,16 @@ func parseRoutes(input []byte) Parsed {
|
|||
}
|
||||
route = Parsed{}
|
||||
|
||||
groups := second_rx.FindStringSubmatch(line)
|
||||
groups := regex.routes.second.FindStringSubmatch(line)
|
||||
first, groups := groups[0], groups[1:]
|
||||
groups = append([]string{network}, groups...)
|
||||
groups = append([]string{first}, groups...)
|
||||
route = mainRouteDetail(groups, route)
|
||||
} else if type_rx.MatchString(line) {
|
||||
submatch := type_rx.FindStringSubmatch(line)[1]
|
||||
} else if regex.routes.routeType.MatchString(line) {
|
||||
submatch := regex.routes.routeType.FindStringSubmatch(line)[1]
|
||||
route["type"] = strings.Split(submatch, " ")
|
||||
} else if bgp_rx.MatchString(line) {
|
||||
groups := bgp_rx.FindStringSubmatch(line)
|
||||
} else if regex.routes.bgp.MatchString(line) {
|
||||
groups := regex.routes.bgp.FindStringSubmatch(line)
|
||||
bgp := Parsed{}
|
||||
|
||||
if tmp, ok := route["bgp"]; ok {
|
||||
|
@ -204,9 +267,9 @@ func parseRoutes(input []byte) Parsed {
|
|||
|
||||
if groups[1] == "community" {
|
||||
communities := [][]int64{}
|
||||
for _, community := range paren_rx.FindAllString(groups[2], -1) {
|
||||
if community_rx.MatchString(community) {
|
||||
com_groups := community_rx.FindStringSubmatch(community)
|
||||
for _, community := range regex.routes.origin.FindAllString(groups[2], -1) {
|
||||
if regex.routes.community.MatchString(community) {
|
||||
com_groups := regex.routes.community.FindStringSubmatch(community)
|
||||
maj := parseInt(com_groups[1])
|
||||
min := parseInt(com_groups[2])
|
||||
communities = append(communities, []int64{maj, min})
|
||||
|
@ -215,9 +278,9 @@ func parseRoutes(input []byte) Parsed {
|
|||
bgp["communities"] = communities
|
||||
} else if groups[1] == "large_community" {
|
||||
communities := [][]int64{}
|
||||
for _, community := range paren_rx.FindAllString(groups[2], -1) {
|
||||
if large_community_rx.MatchString(community) {
|
||||
com_groups := large_community_rx.FindStringSubmatch(community)
|
||||
for _, community := range regex.routes.origin.FindAllString(groups[2], -1) {
|
||||
if regex.routes.largeCommunity.MatchString(community) {
|
||||
com_groups := regex.routes.largeCommunity.FindStringSubmatch(community)
|
||||
maj := parseInt(com_groups[1])
|
||||
min := parseInt(com_groups[2])
|
||||
pat := parseInt(com_groups[3])
|
||||
|
@ -247,14 +310,13 @@ func parseRoutesCount(input []byte) Parsed {
|
|||
res := Parsed{}
|
||||
lines := getLines(input)
|
||||
|
||||
count_rx := regexp.MustCompile(`^(\d+)\s+of\s+(\d+)\s+routes.*$`)
|
||||
for _, line := range lines {
|
||||
if specialLine(line) {
|
||||
continue
|
||||
}
|
||||
|
||||
if count_rx.MatchString(line) {
|
||||
count := count_rx.FindStringSubmatch(line)[1]
|
||||
if regex.routeCount.countRx.MatchString(line) {
|
||||
count := regex.routeCount.countRx.FindStringSubmatch(line)[1]
|
||||
res["routes"] = parseInt(count)
|
||||
}
|
||||
}
|
||||
|
@ -262,6 +324,175 @@ func parseRoutesCount(input []byte) Parsed {
|
|||
return res
|
||||
}
|
||||
|
||||
func isCorrectChannel(currentIPVersion string) bool {
|
||||
if len(currentIPVersion) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
return currentIPVersion == IPVersion
|
||||
}
|
||||
|
||||
func parseBgp(input string) Parsed {
|
||||
res := Parsed{}
|
||||
routeChanges := Parsed{}
|
||||
|
||||
handlers := []func(string) bool{
|
||||
func(l string) bool { return parseBgpProtocol(l, res) },
|
||||
func(l string) bool { return parseBgpRouteLine(l, res) },
|
||||
func(l string) bool { return parseBgpImportUpdates(l, routeChanges) },
|
||||
func(l string) bool { return parseBgpImportWithdraws(l, routeChanges) },
|
||||
func(l string) bool { return parseBgpExportUpdates(l, routeChanges) },
|
||||
func(l string) bool { return parseBgpExportWithdraws(l, routeChanges) },
|
||||
func(l string) bool { return parseBgpNumberValuesRx(l, res) },
|
||||
func(l string) bool { return parseBgpStringValuesRx(l, res) },
|
||||
}
|
||||
|
||||
lines := getLinesFromString(input)
|
||||
ipVersion := ""
|
||||
for _, line := range lines {
|
||||
if m := regex.bgp.channel.FindStringSubmatch(line); len(m) > 0 {
|
||||
ipVersion = m[1]
|
||||
}
|
||||
|
||||
if isCorrectChannel(ipVersion) {
|
||||
parseLine(line, handlers)
|
||||
}
|
||||
}
|
||||
|
||||
res["route_changes"] = routeChanges
|
||||
|
||||
if _, ok := res["routes"]; !ok {
|
||||
routes := Parsed{}
|
||||
routes["accepted"] = 0
|
||||
routes["filtered"] = 0
|
||||
routes["exported"] = 0
|
||||
routes["preferred"] = 0
|
||||
|
||||
res["routes"] = routes
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func parseLine(line string, handlers []func(string) bool) {
|
||||
for _, h := range handlers {
|
||||
if h(line) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func parseBgpProtocol(line string, res Parsed) bool {
|
||||
groups := regex.bgp.protocol.FindStringSubmatch(line)
|
||||
if groups == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
res["protocol"] = groups[1]
|
||||
res["bird_protocol"] = "BGP"
|
||||
res["table"] = groups[2]
|
||||
res["state"] = groups[3]
|
||||
res["state_changed"] = groups[4]
|
||||
res["connection"] = groups[5]
|
||||
return true
|
||||
}
|
||||
|
||||
func parseBgpRouteLine(line string, res Parsed) bool {
|
||||
groups := regex.bgp.routes.FindStringSubmatch(line)
|
||||
if groups == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
routes := parseBgpRoutes(groups[1])
|
||||
res["routes"] = routes
|
||||
return true
|
||||
}
|
||||
|
||||
func parseBgpImportUpdates(line string, res Parsed) bool {
|
||||
groups := regex.bgp.importUpdates.FindStringSubmatch(line)
|
||||
if groups == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
updates := Parsed{}
|
||||
updates["received"] = parseInt(groups[1])
|
||||
updates["rejected"] = parseInt(groups[2])
|
||||
updates["filtered"] = parseInt(groups[3])
|
||||
updates["ignored"] = parseInt(groups[4])
|
||||
updates["accepted"] = parseInt(groups[5])
|
||||
|
||||
res["import_updates"] = updates
|
||||
return true
|
||||
}
|
||||
|
||||
func parseBgpImportWithdraws(line string, res Parsed) bool {
|
||||
groups := regex.bgp.importWithdraws.FindStringSubmatch(line)
|
||||
if groups == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
updates := Parsed{}
|
||||
updates["received"] = parseInt(groups[1])
|
||||
updates["rejected"] = parseInt(groups[2])
|
||||
updates["filtered"] = parseInt(groups[3])
|
||||
updates["accepted"] = parseInt(groups[4])
|
||||
|
||||
res["import_withdraws"] = updates
|
||||
return true
|
||||
}
|
||||
|
||||
func parseBgpExportUpdates(line string, res Parsed) bool {
|
||||
groups := regex.bgp.exportUpdates.FindStringSubmatch(line)
|
||||
if groups == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
updates := Parsed{}
|
||||
updates["received"] = parseInt(groups[1])
|
||||
updates["rejected"] = parseInt(groups[2])
|
||||
updates["ignored"] = parseInt(groups[3])
|
||||
updates["accepted"] = parseInt(groups[4])
|
||||
|
||||
res["export_updates"] = updates
|
||||
return true
|
||||
}
|
||||
|
||||
func parseBgpExportWithdraws(line string, res Parsed) bool {
|
||||
groups := regex.bgp.exportWithdraws.FindStringSubmatch(line)
|
||||
if groups == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
updates := Parsed{}
|
||||
updates["received"] = parseInt(groups[1])
|
||||
updates["accepted"] = parseInt(groups[3])
|
||||
|
||||
res["export_withdraws"] = updates
|
||||
return true
|
||||
}
|
||||
|
||||
func parseBgpNumberValuesRx(line string, res Parsed) bool {
|
||||
groups := regex.bgp.numericValue.FindStringSubmatch(line)
|
||||
if groups == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
key := treatKey(groups[1])
|
||||
res[key] = parseInt(groups[2])
|
||||
return true
|
||||
}
|
||||
|
||||
func parseBgpStringValuesRx(line string, res Parsed) bool {
|
||||
groups := regex.bgp.stringValue.FindStringSubmatch(line)
|
||||
if groups == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
key := treatKey(groups[1])
|
||||
res[key] = groups[2]
|
||||
return true
|
||||
}
|
||||
|
||||
// Will snake_case a value like that:
|
||||
// I am a Weird stRiNg -> i_am_a_weird_string
|
||||
func treatKey(key string) string {
|
||||
|
@ -275,11 +506,13 @@ func parseInt(from string) int64 {
|
|||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return val
|
||||
}
|
||||
|
||||
func parseBgpRoutes(input string) Parsed {
|
||||
routes := Parsed{}
|
||||
|
||||
// Input: 1 imported, 0 filtered, 2 exported, 1 preferred
|
||||
tokens := strings.Split(input, ",")
|
||||
for _, token := range tokens {
|
||||
|
@ -287,105 +520,6 @@ func parseBgpRoutes(input string) Parsed {
|
|||
content := strings.Split(token, " ")
|
||||
routes[content[1]] = parseInt(content[0])
|
||||
}
|
||||
|
||||
return routes
|
||||
}
|
||||
|
||||
func parseBgp(input string) Parsed {
|
||||
res := Parsed{}
|
||||
lines := getLinesFromString(input)
|
||||
route_changes := Parsed{}
|
||||
|
||||
bgp_rx := regexp.MustCompile(`^([\w\.:]+)\s+BGP\s+(\w+)\s+(\w+)\s+([0-9]{4}-[0-9]{2}-[0-9]{2}\s+[0-9]{2}:[0-9]{2}:[0-9]{2})\s*(\w+)?.*$`)
|
||||
num_val_rx := regexp.MustCompile(`^\s+([^:]+):\s+([\d]+)\s*$`)
|
||||
str_val_rx := regexp.MustCompile(`^\s+([^:]+):\s+(.+)\s*$`)
|
||||
|
||||
// routes_rx := regexp.MustCompile(`^\s+Routes:\s+(\d+)\s+imported,\s+(\d+)\s+filtered,\s+(\d+)\s+exported,\s+(\d+)\s+preferred\s*$`)
|
||||
routes_rx := regexp.MustCompile(`^\s+Routes:\s+(.*)`)
|
||||
|
||||
imp_updates_rx := regexp.MustCompile(`^\s+Import updates:\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s*$`)
|
||||
imp_withdraws_rx := regexp.MustCompile(`^\s+Import withdraws:\s+(\d+)\s+(\d+)\s+\-\-\-\s+(\d+)\s+(\d+)\s*$`)
|
||||
exp_updates_rx := regexp.MustCompile(`^\s+Export updates:\s+(\d+)\s+(\d+)\s+(\d+)\s+\-\-\-\s+(\d+)\s*$`)
|
||||
exp_withdraws_rx := regexp.MustCompile(`^\s+Export withdraws:\s+(\d+)(\s+\-\-\-){2}\s+(\d+)\s*$`)
|
||||
for _, line := range lines {
|
||||
if bgp_rx.MatchString(line) {
|
||||
groups := bgp_rx.FindStringSubmatch(line)
|
||||
|
||||
res["protocol"] = groups[1]
|
||||
res["bird_protocol"] = "BGP"
|
||||
res["table"] = groups[2]
|
||||
res["state"] = groups[3]
|
||||
res["state_changed"] = groups[4]
|
||||
res["connection"] = groups[5]
|
||||
} else if routes_rx.MatchString(line) {
|
||||
groups := routes_rx.FindStringSubmatch(line)
|
||||
routes := parseBgpRoutes(groups[1])
|
||||
res["routes"] = routes
|
||||
} else if imp_updates_rx.MatchString(line) {
|
||||
updates := Parsed{}
|
||||
groups := imp_updates_rx.FindStringSubmatch(line)
|
||||
|
||||
updates["received"] = parseInt(groups[1])
|
||||
updates["rejected"] = parseInt(groups[2])
|
||||
updates["filtered"] = parseInt(groups[3])
|
||||
updates["ignored"] = parseInt(groups[4])
|
||||
updates["accepted"] = parseInt(groups[5])
|
||||
|
||||
route_changes["import_updates"] = updates
|
||||
} else if imp_withdraws_rx.MatchString(line) {
|
||||
updates := Parsed{}
|
||||
groups := imp_withdraws_rx.FindStringSubmatch(line)
|
||||
|
||||
updates["received"] = parseInt(groups[1])
|
||||
updates["rejected"] = parseInt(groups[2])
|
||||
updates["filtered"] = parseInt(groups[3])
|
||||
updates["accepted"] = parseInt(groups[4])
|
||||
|
||||
route_changes["import_withdraws"] = updates
|
||||
} else if exp_updates_rx.MatchString(line) {
|
||||
updates := Parsed{}
|
||||
groups := exp_updates_rx.FindStringSubmatch(line)
|
||||
|
||||
updates["received"] = parseInt(groups[1])
|
||||
updates["rejected"] = parseInt(groups[2])
|
||||
updates["ignored"] = parseInt(groups[3])
|
||||
updates["accepted"] = parseInt(groups[4])
|
||||
|
||||
route_changes["export_updates"] = updates
|
||||
} else if exp_withdraws_rx.MatchString(line) {
|
||||
updates := Parsed{}
|
||||
groups := exp_withdraws_rx.FindStringSubmatch(line)
|
||||
|
||||
updates["received"] = parseInt(groups[1])
|
||||
updates["accepted"] = parseInt(groups[3])
|
||||
|
||||
route_changes["export_withdraws"] = updates
|
||||
} else if num_val_rx.MatchString(line) {
|
||||
groups := num_val_rx.FindStringSubmatch(line)
|
||||
|
||||
key := treatKey(groups[1])
|
||||
|
||||
res[key] = parseInt(groups[2])
|
||||
} else if str_val_rx.MatchString(line) {
|
||||
groups := str_val_rx.FindStringSubmatch(line)
|
||||
|
||||
key := treatKey(groups[1])
|
||||
|
||||
res[key] = groups[2]
|
||||
}
|
||||
}
|
||||
|
||||
res["route_changes"] = route_changes
|
||||
|
||||
if _, ok := res["routes"]; !ok {
|
||||
routes := Parsed{}
|
||||
|
||||
routes["accepted"] = 0
|
||||
routes["filtered"] = 0
|
||||
routes["exported"] = 0
|
||||
routes["preferred"] = 0
|
||||
|
||||
res["routes"] = routes
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ func isModuleEnabled(module string, modulesEnabled []string) bool {
|
|||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -122,6 +123,7 @@ func main() {
|
|||
birdConf := conf.Bird
|
||||
if *bird6 {
|
||||
birdConf = conf.Bird6
|
||||
bird.IPVersion = "6"
|
||||
}
|
||||
|
||||
PrintServiceInfo(conf, birdConf)
|
||||
|
|
Loading…
Add table
Reference in a new issue