diff --git a/bird/parser.go b/bird/parser.go index d682eb2..9eb50ca 100644 --- a/bird/parser.go +++ b/bird/parser.go @@ -104,8 +104,108 @@ func parseSymbols(input []byte) Parsed { return res } +func mainRouteDetail(groups []string, route Parsed) Parsed { + route["network"] = groups[1] + route["gateway"] = groups[2] + route["interface"] = groups[3] + route["from_protocol"] = groups[4] + route["age"] = groups[5] + route["learnt_from"] = groups[6] + route["primary"] = groups[7] == "*" + if val, err := strconv.ParseInt(groups[8], 10, 64); err != nil { + route["metric"] = 0 + } else { + route["metric"] = val + } + return route +} + func parseRoutes(input []byte) Parsed { - return Parsed{} + res := 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+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+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+(\w+)\s*$`) + community_rx := regexp.MustCompile(`^\((\d+),(\d+)\)`) + for _, line := range lines { + if specialLine(line) || (len(route) == 0 && emptyLine(line)) { + continue + } + + if start_def_rx.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) { + routes = append(routes, route) + var network string + if tmp, ok := route["network"]; ok { + if val, ok := tmp.(string); ok { + network = val + } else { + continue + } + } else { + continue + } + route = Parsed{} + + groups := second_rx.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) { + route["type"] = strings.Split(type_rx.FindStringSubmatch(line)[1], + " ") + } else if bgp_rx.MatchString(line) { + groups := bgp_rx.FindStringSubmatch(line) + bgp := Parsed{} + + if tmp, ok := route["bgp"]; ok { + if val, ok := tmp.(Parsed); ok { + bgp = val + } + } + + if groups[1] == "community" { + communities := [][]int64{} + for _, community := range strings.Split(groups[2], " ") { + if community_rx.MatchString(community) { + com_groups := community_rx.FindStringSubmatch(community) + maj, err := strconv.ParseInt(com_groups[1], 10, 64) + if err != nil { + continue + } + min, err := strconv.ParseInt(com_groups[2], 10, 64) + if err != nil { + continue + } + communities = append(communities, []int64{maj, min}) + } + bgp["communities"] = communities + } + } else { + bgp[groups[1]] = groups[2] + } + + route["bgp"] = bgp + } + } + + if len(route) > 0 { + routes = append(routes, route) + } + + res["routes"] = routes + return res } func parseRoutesCount(input []byte) Parsed { diff --git a/birdwatcher.go b/birdwatcher.go index b29a6e6..566b6ca 100644 --- a/birdwatcher.go +++ b/birdwatcher.go @@ -113,7 +113,7 @@ func main() { r := httprouter.New() r.GET("/status", Status) - r.GET("/routes", Routes) + r.GET("/routes/protocol/:protocol", ProtoRoutes) r.GET("/protocols", Protocols) log.Fatal(http.ListenAndServe(":29184", r)) diff --git a/routes.go b/routes.go index ac8a7bd..465c2ba 100644 --- a/routes.go +++ b/routes.go @@ -3,13 +3,15 @@ package main import ( "encoding/json" "github.com/julienschmidt/httprouter" + "github.com/mchackorg/birdwatcher/bird" "net/http" ) -func Routes(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { +func ProtoRoutes(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { res := make(map[string]interface{}) res["api"] = GetApiInfo() + res["routes"] = bird.RoutesProto(ps.ByName("protocol"))["routes"] js, _ := json.Marshal(res)