libBGPStream Tutorial

libBGPStream is a C library that facilitate the creation of a sorted stream of BGP records.

Below we provide the following tutorials:


Get familiar with the API: count the BGP elems

In this example we show how to use most of the C library API functions to count the BGP elems in the current stream. The example is fully functioning and it can be compiled and run using the following commands:

$ gcc ./bgpstream-tutorial.c  -lbgpstream -o ./tutorial
$ ./tutorial
Read 5519 elems


The program instantiates an instance of BGPStream that uses the CAIDA broker as data interface (default), and it counts the elems that match the filters (collectors, record type, and time).


Step by step description

The first step in each program using libBGPStream, is to allocate memory for a BGPStream instance and for a BGPStream record. The latter is a re-usable memory allocation that is going to contain the most recent record read.

bgpstream_t *bs = bs = bgpstream_create();
bgpstream_record_t *bs_record = bgpstream_record_create();


The second step consists in customizing the stream using the project, collector, type, and time interval filters. The time interval filter is mandatory, whereas the others are optional. In this specific case, we are configuring the stream to return the BGP records read from Updates dumps generated by RRC06 and Route View Jinx collectors, having a timestamp in the interval 10:10:10 - 11:11:11 Sun, 10 Oct 2010 GMT.


bgpstream_add_filter(bs, BGPSTREAM_FILTER_TYPE_COLLECTOR, "rrc06"); bgpstream_add_filter(bs, BGPSTREAM_FILTER_TYPE_COLLECTOR, "route-views.jinx"); bgpstream_add_filter(bs, BGPSTREAM_FILTER_TYPE_RECORD_TYPE, "updates"); bgpstream_add_interval_filter(bs,1286705410,1286709071);


At this point we can start the stream, and repeatedly ask for new BGP records and BGP elems (the bs_elem pointer points to memory that is borrowed from BGPStream, one has to use the API copy function to own the memory). Each time a valid record is read, we extract the elems that it contains, and we increment a counter.

bgpstream_elem_t *bs_elem = NULL;

do
  {  
   get_next_ret = bgpstream_get_next_record(bs, bs_record);
   if(get_next_ret && bs_record->status == BGPSTREAM_RECORD_STATUS_VALID_RECORD)
    {
     while((bs_elem = bgpstream_record_get_next_elem (bs_record)) != NULL)
      {
       elem_counter++;
      }
    }
  }
while(get_next_ret > 0);


Once the entire stream has been read, we can print the results, and de-allocate the memory allocated for the BGPStream record and the BGPStream instance.

printf("\tRead %d elems\n", elem_counter);

bgpstream_record_destroy(bs_record);
bgpstream_destroy(bs);


Complete Example

Get the code.

#include <stdio.h>
#include "bgpstream.h"

int
main()
{
  /* Allocate memory for a bgpstream instance */
  bgpstream_t *bs = bs = bgpstream_create();
  if(!bs) {
    fprintf(stderr, "ERROR: Could not create BGPStream instance\n");
    return -1;
  }

  /* Allocate memory for a re-usable bgprecord instance */
  bgpstream_record_t *bs_record = bgpstream_record_create();
  if(bs_record == NULL)
    {
      fprintf(stderr, "ERROR: Could not create BGPStream record\n");
      return -1;
    }

  /* The broker interface is set by default */

  /* Select bgp data from RRC06 and route-views.jinx collectors only */
  bgpstream_add_filter(bs, BGPSTREAM_FILTER_TYPE_COLLECTOR, "rrc06");
  bgpstream_add_filter(bs, BGPSTREAM_FILTER_TYPE_COLLECTOR, "route-views.jinx");

  /* Process updates only */
  bgpstream_add_filter(bs, BGPSTREAM_FILTER_TYPE_RECORD_TYPE, "updates");

  /* Select a time interval to process:
   * Sun, 10 Oct 2010 10:10:10 GMT -  Sun, 10 Oct 2010 11:11:11 GMT */
  bgpstream_add_interval_filter(bs,1286705410,1286709071);

  /* Start bgpstream */
  if(bgpstream_start(bs) < 0) {
    fprintf(stderr, "ERROR: Could not init BGPStream\n");
    return -1;
  }

  int get_next_ret = 0;
  int elem_counter = 0;

  /* Pointer to a bgpstream elem, memory is borrowed from bgpstream,
   * use the elem_copy function to own the memory */
  bgpstream_elem_t *bs_elem = NULL;

  /* Read the stream of records */
  do
    {
      /* Get next record */
      get_next_ret = bgpstream_get_next_record(bs, bs_record);
      /* Check if there are new records and if they are valid records */
      if(get_next_ret && bs_record->status == BGPSTREAM_RECORD_STATUS_VALID_RECORD)
        {
          /* Get next elem in the record */
          while((bs_elem = bgpstream_record_get_next_elem (bs_record)) != NULL)
            {
              elem_counter++;
            }
        }
    }
  while(get_next_ret > 0);

  /* Print the number of elems */
  printf("\tRead %d elems\n", elem_counter);

  /* De-allocate memory for the bgpstream record */
  bgpstream_record_destroy(bs_record);

  /* De-allocate memory for the bgpstream */
  bgpstream_destroy(bs);

  return 0;
}


Prefix monitoring

In this second example, we show how to implement a program that outputs all the announcements and withdrawal messages for a specific prefix, 2403:f600::/32, observed by Route Views 2 and RRC00 during the time interval 01:20:10 - 06:32:15 on Tue, 12 Aug 2014 UTC. The example is fully functioning and it can be compiled and run using the following commands:

$ gcc ./bgpstream-pfx-mon.c  -lbgpstream -o ./pfx-monitoring
$ ./pfx-monitoring
   U|A|1407813784|ris|rrc00|6881|2a02:38::2|2403:f600::/32|2a02:38::2|6881 6939 4826 38456 55722|55722||
   U|W|1407813784|ris|rrc00|50300|2a00:1c10:10::8|2403:f600::/32|||||
   U|A|1407813786|ris|rrc00|57381|2001:67c:24e4:1::1|2403:f600::/32|2001:67c:24e4:1::1|57381 50304 10026 38456 55722|55722||
   ...
   U|A|1407814216|ris|rrc00|57381|2001:67c:24e4:1::1|2403:f600::/32|2001:67c:24e4:1::1|57381 42708 10026 38456 55722|55722||
   U|A|1407814218|ris|rrc00|29608|2a01:678::2|2403:f600::/32|2a01:678::2|29608 6939 4826 38456 55722|55722||
   U|A|1407814228|ris|rrc00|45896|2001:df0:2e8:1000::1|2403:f600::/32|2001:df0:2e8:1000::1|45896 4826 38456 55722|55722||


Step by step description

The program stores in a pfx_storage structure the prefix to monitor. The user can provide the prefix as a string and then convert it into the BGPStream prefix data structure using the BGPStream utils.

bgpstream_pfx_storage_t my_pfx;
bgpstream_str2pfx( "2403:f600::/32", &my_pfx);


The configuration of the stream through a set of filters is similar to the previous example.

bgpstream_add_filter(bs, BGPSTREAM_FILTER_TYPE_COLLECTOR, "rrc00");
bgpstream_add_filter(bs, BGPSTREAM_FILTER_TYPE_COLLECTOR, "route-views2");

bgpstream_add_filter(bs, BGPSTREAM_FILTER_TYPE_RECORD_TYPE, "updates");

bgpstream_add_filter(bs, BGPSTREAM_FILTER_TYPE_ELEM_PREFIX, "2403:f600::/32");


bgpstream_add_interval_filter(bs, 1407806410, 1407825135);


The prefix filter select 2403:f600::/32 and more specifics. Finally, for each elem, the program prints out only the information associated with announcements and withdrawals related to the exact prefix.

if (( elem->type == BGPSTREAM_ELEM_TYPE_ANNOUNCEMENT ||
      elem->type == BGPSTREAM_ELEM_TYPE_WITHDRAWAL) &&
      bgpstream_pfx_storage_equal(&my_pfx, &elem->prefix))
      { 
       bgpstream_record_elem_snprintf(buffer, 1024, record, elem);
       fprintf(stdout, "%s\n", buffer);
      }


Complete Example

Get the code.

#include <stdio.h>
#include "bgpstream.h"

int main(int argc, const char **argv)
{
  bgpstream_t *bs = bgpstream_create();
  bgpstream_record_t *record = bgpstream_record_create();
  bgpstream_elem_t *elem = NULL;
  char buffer[1024];

  /* Define the prefix to monitor: 2403:f600::/32 */
  bgpstream_pfx_storage_t my_pfx;
  if(bgpstream_str2pfx( "2403:f600::/32", &my_pfx) == NULL)
    {
      fprintf(stderr, "Error: invalid prefix\n");
      return -1;
    }

  /* Set metadata filters */
  bgpstream_add_filter(bs, BGPSTREAM_FILTER_TYPE_COLLECTOR, "rrc00");
  bgpstream_add_filter(bs, BGPSTREAM_FILTER_TYPE_COLLECTOR, "route-views2");
  bgpstream_add_filter(bs, BGPSTREAM_FILTER_TYPE_RECORD_TYPE, "updates");
  bgpstream_add_filter(bs, BGPSTREAM_FILTER_TYPE_ELEM_PREFIX, "2403:f600::/32");
  /* Time interval: 01:20:10 - 06:32:15 on Tue, 12 Aug 2014 UTC */
  bgpstream_add_interval_filter(bs, 1407806410, 1407825135);

  /* Start the stream */
  bgpstream_start(bs);

  /* Read the stream of records */
  while (bgpstream_get_next_record(bs, record) > 0) {
    /* Ignore invalid records */
    if (record->status != BGPSTREAM_RECORD_STATUS_VALID_RECORD) {
      continue;
    }
    /* Extract elems from the current record */
    while ((elem = bgpstream_record_get_next_elem(record)) != NULL) {
      /* Select only announcements and withdrawals, */
      /* and only elems that carry information for 2403:f600::/32 */
      if ((elem->type == BGPSTREAM_ELEM_TYPE_ANNOUNCEMENT ||
           elem->type == BGPSTREAM_ELEM_TYPE_WITHDRAWAL) &&
          bgpstream_pfx_storage_equal(&my_pfx, &elem->prefix)) {
        /* Print the BGP information */
        bgpstream_record_elem_snprintf(buffer, 1024, record, elem);
        fprintf(stdout, "%s\n", buffer);
      }
    }
  }

  bgpstream_destroy(bs);
  bgpstream_record_destroy(record);
  return 0;
}