diff --git a/bird/bird.go b/bird/bird.go index 9ed71d8..f1dc80b 100644 --- a/bird/bird.go +++ b/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 } diff --git a/bird/config.go b/bird/config.go index 673cdb1..bfcdaed 100644 --- a/bird/config.go +++ b/bird/config.go @@ -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 { diff --git a/bird/parser.go b/bird/parser.go index 5b899c7..b19e7b3 100644 --- a/bird/parser.go +++ b/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 -} diff --git a/birdwatcher.go b/birdwatcher.go index 2165519..761d37c 100644 --- a/birdwatcher.go +++ b/birdwatcher.go @@ -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)