Intro

Git repo with the follow a long examples.

This is a small demo environment I quickly tossed together to solve the problem of monitoring routes within a environment. I normally try to solve these sorts of issues with something like openconfig specifically using AFT’s in this scenario. AFT’s will in fact stream the routing table. However, the general issue here is that it streams it with a pointer to he next hop and interface.

So That being said if you had a list of routes you would then have to have another stream setup to provide both the next hop and outgoing interface.

I generally like SuzieQ and find it solves a lot of issue with both the CLI and the Rest API since it tends to have all the data from devices. By all the data referring to Routes, arps, mac addresses etc.

SuzieQ

SuzieQ is a Multivendor poller that can poll device data and then simply present for each network operating system in a normalized fashion of the data. So in this scenario I care about routing tables. I would like to normalize the routes per network os and have it presented to me in the same data structure. SuzieQ can do this. SuzieQ can be accessed via the CLI and a Restapi. SuzieQ uses a lot of really interesting mechanisms to allow for someone to correlate all of this data in one central location. I would highly advize someone who is interested to simply read all of their docs and go through the examples. To get started is rather easy since its available in container fashion.

TiG stack and SuzieQ

I think most have heard of TiG Stack(Telegraf, InfluxDB and Grafana) this makes up a really good observability stack leveraged by many people for many different use cases within the realm of infrastructure.

The idea here is to use telegraf to talk to the SuzieQ API to ask it for routes and then take those routes to push into Influx to be further graphed within grafana. In order to do that I need to create a telegraf plugin which can be ran as a binary. All of this is within the git repo what is nice is that when running SuzieQ it gives you a swagger API which can then be found within the /api/docs folder.

Before jumping into the telegraf code lets take a look at the overall picture.

1

Starting from telegraf it will ask SuzieQ leveraging the SuzieQ API for routes. Those routes are then pushed into Influx and further graphed.

A small picture of the telegraf.conf file from the git repo.

[[inputs.suzieq]]
  ## CVP Address
  url = "172.20.20.102"
  port = 8000
  enable_tls = false
  token = "496157e6e869ef7f3d6ecb24a6f6d847b224ee4f"

[[outputs.influxdb_v2]]
  ## The URLs of the InfluxDB cluster nodes.
  ##
  ## Multiple URLs can be specified for a single cluster, only ONE of the
  ## urls will be written to each interval.
  ## urls exp: http://127.0.0.1:8086
  urls = ["http://172.20.20.104:8086"]

  ## Token for authentication.
  token = "sqtoken"
  ## Organization is the name of the organization you wish to write to; must exist.
  organization = "sq"

  ## Destination bucket to write into.
  bucket = "sq"

The [[inputs.suzieq]] is part of the telegraf plugin I created. This is nothing real ground shattering at all to create such a thing. Telegraf as long as you know some Go you can easily create a middlewear telegraf plugin.

Telegraf plugin code.

Taking a look at the relevent code here

This is actually quite simple.

The Go structs
type SuzieQ struct {
	Url       string `toml:"url"`
	Token     string `toml:"token"`
	EnableTLS bool   `toml:"enable_tls"`
	Port      int    `toml:"port"`
	Log       telegraf.Logger
	Interval  *time.Ticker `toml:"interval"`
	done      chan bool
}

type NetworkRoutes []struct {
	Action     string   `json:"action"`
	Hostname   string   `json:"hostname"`
	Ipvers     int64    `json:"ipvers"`
	Namespace  string   `json:"namespace"`
	NexthopIps []string `json:"nexthopIps"`
	Oifs       []string `json:"oifs"`
	Preference int64    `json:"preference"`
	Prefix     string   `json:"prefix"`
	Protocol   string   `json:"protocol"`
	Source     string   `json:"source"`
	Timestamp  int64    `json:"timestamp"`
	Vrf        string   `json:"vrf"`
}

Within telegraf plugins there is generally what I would call a main struct. The SuzieQ struct in this scenario will match the options within the input.suzieq from telegraf.conf. The NetworkRoutes struct is simply a response to the JSON once it is marshalled from SuzieQ.

Gather method
func (c *SuzieQ) Gather(acc telegraf.Accumulator) error {
	req, err := http.NewRequest("GET", "https://"+c.Url+":"+strconv.Itoa(c.Port)+"/api/v2/route/show?access_token="+c.Token, nil)
	if err != nil {
		fmt.Println(err)
	}
	req.Header.Add("Accept", "application/json")
	//To do tls certs in case of if else

	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}

	client := &http.Client{Transport: tr}
	resp, err := client.Do(req)
	if err != nil {
		fmt.Println(err)
	}
	defer resp.Body.Close()

	responseData, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("Cannot marshall data", err)
	}

	JsonResponse := NetworkRoutes{}
	//Unmarshall it
	err = json.Unmarshal(responseData, &JsonResponse)
	// Show how type values work.
	var fields = make(map[string]interface{}, len(NetworkRoutes{}))
	var tags = map[string]string{}
	for _, v := range JsonResponse {
		tags["Device"] = v.Hostname
		tags["VRF"] = v.Vrf
		tags["RoutingProtocol"] = v.Protocol
		tags["Timestamp"] = strconv.Itoa(int(v.Timestamp))
		for _, nh := range v.NexthopIps {
			tags["nexthops"] = nh
		}
		for _, oi := range v.Oifs {
			tags["OutgoingInterfaces"] = oi
		}
		fields["Prefix"] = v.Prefix
		acc.AddFields("NetworkRoutes", fields, tags)
	}
	return nil
}

Like I said this is extremely simplistic. Gather is called within Telegrafs code not here and gather does exactly what you would imagine. This is where the plugin simply gathers information and pushes it into telegraf as a whole. So all in all all this method does is talk to the suzieq api and structures the response data and pushes the data into telegraf.. it is that simple.

Initializing
func init() {
	inputs.Add("suzieq", func() telegraf.Input {
		return &SuzieQ{}
	})
}

The init happens before anything and simply adds suzieq as a whole.

Grafana outputs

I have all of this within the git repo as mentioned previously, but once this runs its possible to then simply monitor and manage all the routes that are associated within SuzieQ. Here is a simple output of the environment in which we are working with.

2

This means that any routes within the environment will now be present within grafana.

Summary

I find SuzieQ really interesting. I used this for a few internal projectes CICD wise for after the fact. For example, adding config to devices and then polling SuzieQ to make sure that it fit a specific parameter. ie if I had 100 routes prior to this change and now I have 10 this would be a problem. I think for most people SuzieQ fits quite a good need in the realm of networking.

About this telegraf plugin. I can contribute this to Influx/telegraf if someone had a general want or need to do so. It would requite unit tests and a few other things to conform to their standards(All which are good) any questions feel free to reachout if interested.