BGPCorsaro Tutorial

BGPCorsaro is a command-line tool to continuously extract derived data from a BGP stream in regular time bins.Its architecture is based on a pipeline of plugins, which continuously process BGPStream records.

The most used command-line options are:


$ bgpcorsaro -w <start>[,<end>] -x "plugin-name [<plugin-options>]" -O outfile-template [<options>]


Below we provide the following tutorials:


Using the pfxmonitor plugin

Below we describe how to use the pfxmonitor plugin to monitor the prefixes that are usually originated by AS137 (GARR, the Italian Academic and Research Network) over a period of one month.

Step 1: collecting the list of prefixes to monitor

We can generate the list of prefixes announced by AS 137 by redirecting the output of bgpreader to a file. We can focus on the prefixes announced by AS137 on Jan, 1 2015.


$ bgpreader -w1420070400,1420156799 | awk -F"|" '(($2=="R" || $2=="A") && $11=="137"){print $8}' | sort -u 30.136.0.0/16 130.186.0.0/19 130.192.0.0/16 130.251.0.0/16 131.114.0.0/16 131.154.0.0/16 131.175.0.0/16 137.204.0.0/16 138.41.0.0/16 ... 193.43.97.0/24 194.119.192.0/19 2001:760::/32 212.189.128.0/17 2a00:1620::/32 90.147.0.0/16

Let's save the list of prefixes in a file garr_pfxs_20150101.txt.


Step 2: running bgpcorsaro

Now that we have a list of prefixes to monitor we can run bgpcorsaro using the following command:

$ bgpcorsaro -w1420070400,1420077600  -x"pfxmonitor -L ./garr_pfxs_20150101.txt -n 5 -M" -i 300 -O ./%X.txt


We configure bgpcorsaro to process BGPStream records from all available collectors and all kinds of dumps (both RIBs and Updates) for the entire month of January 2015.

-w1420070400,1422748800


We activate pfxmonitor , and we configure the plugin to:

  • read the list of prefixes to monitor from garr_pfxs_20150101.txt
  • consider a <prefix, origin ASn> pair only if it has been seen by at least 5 different peer ASns.
  • consider in the analysis only the prefixes that match exactly one of the prefixes in the list or if they are more specific.
-x"pfxmonitor -L ./garr_pfxs_20150101.txt -n 5 -M" 


We set the interval to be 5 minutes, and the output file to be pfxmonitor.txt

-i 300 -O ./%X.txt


Step 3: taking a look at the results

garr_pfxs_20150101.txt contains 80 unique prefixes (78 IPv4 prefixes, 2 IPv6 prefixes). When running the bgpcorsaro plugin, the output metrics (number of prefixes, and number of announcing ASns) are mostly stable. Numbers change when:

  • some prefixes stop to be announced,
  • new more specific prefixes are announced,
  • other AS announce such space.
bgp.pfxmonitor.ip-space.prefixes_cnt 80 1420070400
bgp.pfxmonitor.ip-space.origin_ASns_cnt 1 1420070400
bgp.pfxmonitor.ip-space.prefixes_cnt 80 1420070700
bgp.pfxmonitor.ip-space.origin_ASns_cnt 1 1420070700
bgp.pfxmonitor.ip-space.prefixes_cnt 80 1420071000
bgp.pfxmonitor.ip-space.origin_ASns_cnt 1 1420071000
bgp.pfxmonitor.ip-space.prefixes_cnt 80 1420071300
bgp.pfxmonitor.ip-space.origin_ASns_cnt 1 1420071300
bgp.pfxmonitor.ip-space.prefixes_cnt 80 1420071600
bgp.pfxmonitor.ip-space.origin_ASns_cnt 1 1420071600
bgp.pfxmonitor.ip-space.prefixes_cnt 80 1420071900
bgp.pfxmonitor.ip-space.origin_ASns_cnt 1 1420071900
...


Creating a new plugin

This tutorial gives some background for the BGPCorsaro plugin architecture and describes how one could go about designing and implementing a new plugin.

Here we show how to implement a new plugin, elemcounter, that counts the number of BGP elems processed each interval and outputs such counters for each BGP elem type.

This tutorial consists of two steps:

  1. Create new files for the new plugin and adding references to the newly created plugin;
  2. Developing the new plugin logic.

Creating Boilerplate Code

In order to develop a new plugin, it is necessary to edit 6 different files. We use elemcounter as the name of the new plugin that we are goin to develop.


1. Edit configure.ac

We add a new line to the configure file to add the new plugin to the configuration. The last [yes] parameter indicates that the plugin is going to be available by default, if set to [no] the user can make it available at configuration time using the option --with-plugin-elemcounter.

ED_WITH_PLUGIN([bgpcorsaro_pfxmonitor],[pfxmonitor],[PFXMONITOR],[yes])
ED_WITH_PLUGIN([bgpcorsaro_pacifier],[pacifier],[PACIFIER],[yes])

ED_WITH_PLUGIN([bgpcorsaro_elemcounter],[elemcounter],[ELEMCOUNTER],[yes])

# this MUST go after all the ED_WITH_PLUGIN macro calls
AC_DEFINE_UNQUOTED([ED_PLUGIN_INIT_ALL_ENABLED], $ED_PLUGIN_INIT_ALL_ENABLED,
           [plugins to call the init macro for in bgpcorsaro_plugin.c])


2. Edit bgpcorsaro/lib/bgpcorsaro_plugin.h

Add a new ID for the new plugin, and, if necessary, update the maximum plugin ID to contain the maximum plugin ID value.

typedef enum bgpcorsaro_plugin_id
{
  /** Prefix Monitor plugin */
  BGPCORSARO_PLUGIN_ID_PFXMONITOR       = 1,

  /** Pacifier plugin */
  BGPCORSARO_PLUGIN_ID_PACIFIER         = 2,

  /** Elem Counter plugin */
  BGPCORSARO_PLUGIN_ID_ELEMCOUNTER      = 3,

  /** Maximum plugin ID assigned */
  BGPCORSARO_PLUGIN_ID_MAX              = BGPCORSARO_PLUGIN_ID_ELEMCOUNTER
} bgpcorsaro_plugin_id_t;


3. Edit bgpcorsaro/lib/bgpcorsaro_plugin.c

Include the plugin's header file in the bgpcorsaro_plugin.c file, i.e. add the following lines:

#ifdef WITH_PLUGIN_ELEMCOUNTER
#include "bgpcorsaro_elemcounter.h"
#endif


4. Edit bgpcorsaro/lib/Makefile.am

Include the plugin's header and source files to the Makefile so that it gets built with bgpcorsaro.

if WITH_PLUGIN_ELEMCOUNTER
PLUGIN_SRC+=bgpcorsaro_elemcounter.c bgpcorsaro_elemcounter.h
endif


5. Create bgpcorsaro/lib/plugins/bgpcorsaro_elemcounter.h

Create the header file (code)

#ifndef __BGPCORSARO_ELEMCOUNTER_H
#define __BGPCORSARO_ELEMCOUNTER_H

#include "bgpcorsaro_plugin.h"

/** @file
 *
 * @brief Header file which exports bgpcorsaro_elemcounter plugin API
 *
 */

BGPCORSARO_PLUGIN_GENERATE_PROTOS(bgpcorsaro_elemcounter)

#endif /* __BGPCORSARO_ELEMCOUNTER_H */


6. Create bgpcorsaro/lib/plugins/bgpcorsaro_elemcounter.c

Below is the minimum set of functions that need to be defined for the plugin to work properly. This file is a working template, i.e. no operations are performed are performed by the plugin. A complete implementation will be described in the next section. The template can be downloaded (here).

#include "config.h"
#include "bgpcorsaro_int.h"

#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "utils.h"
#include "wandio_utils.h"

#include "bgpcorsaro_io.h"
#include "bgpcorsaro_log.h"
#include "bgpcorsaro_plugin.h"

#include "bgpcorsaro_elemcounter.h"

/** @file
 *
 * @brief Bgpcorsaro Elem Counter plugin implementation
 *
 */

/** The name of this plugin */
#define PLUGIN_NAME "elemcounter"

/** The version of this plugin */
#define PLUGIN_VERSION "0.1"

/** Common plugin information across all instances */
static bgpcorsaro_plugin_t bgpcorsaro_elemcounter_plugin = {
  PLUGIN_NAME,                                  /* name */
  PLUGIN_VERSION,                               /* version */
  BGPCORSARO_PLUGIN_ID_ELEMCOUNTER,                 /* id */
  BGPCORSARO_PLUGIN_GENERATE_PTRS(bgpcorsaro_elemcounter), /* func ptrs */
  BGPCORSARO_PLUGIN_GENERATE_TAIL,
};


/** Holds the state for an instance of this plugin */
struct bgpcorsaro_elemcounter_state_t {

  /* useful variables HERE*/

};


/** Extends the generic plugin state convenience macro in bgpcorsaro_plugin.h */
#define STATE(bgpcorsaro)                        \
  (BGPCORSARO_PLUGIN_STATE(bgpcorsaro, elemcounter, BGPCORSARO_PLUGIN_ID_ELEMCOUNTER))

/** Extends the generic plugin plugin convenience macro in bgpcorsaro_plugin.h */
#define PLUGIN(bgpcorsaro)                        \
  (BGPCORSARO_PLUGIN_PLUGIN(bgpcorsaro, BGPCORSARO_PLUGIN_ID_ELEMCOUNTER))

/** Print usage information to stderr */
static void usage(bgpcorsaro_plugin_t *plugin)
{
  fprintf(stderr,
      "plugin usage: %s [options HERE]\n",
      plugin->argv[0]);
}

/** Parse the arguments given to the plugin */
static int parse_args(bgpcorsaro_t *bgpcorsaro)
{
  bgpcorsaro_plugin_t *plugin = PLUGIN(bgpcorsaro);
  int opt;

  if(plugin->argc <= 0)
    {
      return 0;
    }

  /* NB: remember to reset optind to 1 before using getopt! */
  optind = 1;

  while((opt = getopt(plugin->argc, plugin->argv, ":h?")) >= 0)
    {
      switch(opt)
    {
    case 'h':
    case '?':
    case ':':
    default:
      usage(plugin);
      return -1;
    }
    }

  return 0;
}




/* == PUBLIC PLUGIN FUNCS BELOW HERE == */

/** Implements the alloc function of the plugin API */
bgpcorsaro_plugin_t *bgpcorsaro_elemcounter_alloc(bgpcorsaro_t *bgpcorsaro)
{
  return &bgpcorsaro_elemcounter_plugin;
}

/** Implements the init_output function of the plugin API */
int bgpcorsaro_elemcounter_init_output(bgpcorsaro_t *bgpcorsaro)
{
  struct bgpcorsaro_elemcounter_state_t *state;
  bgpcorsaro_plugin_t *plugin = PLUGIN(bgpcorsaro);
  assert(plugin != NULL);

  if((state = malloc_zero(sizeof(struct bgpcorsaro_elemcounter_state_t))) == NULL)
    {
      bgpcorsaro_log(__func__, bgpcorsaro,
             "could not malloc bgpcorsaro_elemcounter_state_t");
      goto err;
    }
  bgpcorsaro_plugin_register_state(bgpcorsaro->plugin_manager, plugin, state);

  /* initialize state variables HERE */

  /* parse the arguments */
  if(parse_args(bgpcorsaro) != 0)
    {
      return -1;
    }

  return 0;

 err:
  bgpcorsaro_elemcounter_close_output(bgpcorsaro);
  return -1;
}

/** Implements the close_output function of the plugin API */
int bgpcorsaro_elemcounter_close_output(bgpcorsaro_t *bgpcorsaro)
{

  struct bgpcorsaro_elemcounter_state_t *state = STATE(bgpcorsaro);

  if(state != NULL)
    {

      /* deallocate dynamic memory in state HERE */

      bgpcorsaro_plugin_free_state(bgpcorsaro->plugin_manager, PLUGIN(bgpcorsaro));
    }
  return 0;
}

/** Implements the start_interval function of the plugin API */
int bgpcorsaro_elemcounter_start_interval(bgpcorsaro_t *bgpcorsaro,
                                          bgpcorsaro_interval_t *int_start)
{

  /* interval start operations HERE */

  return 0;
}

/** Implements the end_interval function of the plugin API */
int bgpcorsaro_elemcounter_end_interval(bgpcorsaro_t *bgpcorsaro,
                                        bgpcorsaro_interval_t *int_end)
{

  /* interval end operations HERE */

  return 0;
}

/** Implements the process_record function of the plugin API */
int bgpcorsaro_elemcounter_process_record(bgpcorsaro_t *bgpcorsaro,
                                          bgpcorsaro_record_t *record)
{

  /* interval process record operations HERE */

  return 0;
}


7. Build and run

In order to build the bgpcorsaro with the elemcounter plugin, it is necessary to run the following commands:

$ ./autogen.sh
$ ./configure
   ...
   configure: ---- BGPCorsaro configuration ---- 
   checking for the monitor name to use... chiara-mbp.caida.org
   checking whether to monitor plugin runtimes... no
   checking whether to build with pfxmonitor plugin... yes
   checking whether to build with pacifier plugin... yes
   checking whether to build with elemcounter plugin... yes
   configure: ----------------------------------
   ...
$ make
$ make install


Autogen and configure are required as we modified the configure.ac and the Makefile.am files. From now on, if we just modify the bgpcorsaro_elemcounter.c file, re-compiling requires only two steps:

$ make
$ make install


We can verify that the elemcounter plugin is available by taking a look at the output of the usage function:

$ bgpcorsaro -h 
   ...
   -x <plugin>    enable the given plugin (default: all)*
                   available plugins:
                    - pfxmonitor
                    - pacifier
                    - elemcounter
                    use -p "<plugin_name> -?" to see plugin options
   ... 

If we run bgpcorsaro with elemcounter activated, no operations are performed. Let's see in next section how to implement a useful plugin.


Developing the elemcounter plugin

First of all, let's define in a more precise way the output expected from the plugin:

At the end of each interval we want to output the number of RIB, announcement, withdrawal, and state message elems observed within the interval. We support two output formats, i.e.: single line (all counters written in a single line, default) and multiline (one line per counter type).

Below we discuss the datastructures that we maintain in the state and how we modify them each time the interval starts, ends, or a new record is available.


elemcounter state: allocation, initialization, deallocation

We maintain two variables in the elemcounter state structure:

  • an array of int that will store the number of elems observed in each interval (for each type)
  • a flag to remember the output format specified by the user.
struct bgpcorsaro_elemcounter_state_t {

  /* elem counter array, one counter per 
   * BGPStream elem type*/
  int elem_cnt[5];

  /* 0 if the preferred output is singleline (default)
   * 1 if the preferred output is multiline */
  int multiline_flag;

};


The elemcounter state is allocated and initialized using the bgpcorsaro_elemcounter_init_output function, the state can also be changed by the parse_args function that read the arguments passed to the plugin.

/* in int bgpcorsaro_elemcounter_init_output(bgpcorsaro_t *bgpcorsaro) */
 ... 
/* allocate memory for state variables:
 * elemcounter does not have any dynamic memory variable
 * so no malloc is required */

/* initialize state variables */
int i;
for(i=0; i< 5; i++)
  {
    state->elem_cnt[i] = 0;
  }

/* single line is the default output format */
state->multiline_flag = 0; 
...


/* in static int parse_args(bgpcorsaro_t *bgpcorsaro) */
... 
while((opt = getopt(plugin->argc, plugin->argv, ":m?")) >= 0)
{
 switch(opt)
 {
   case 'm':
     state->multiline_flag = 1;
     break;
   case '?':
   case ':':
   default:
     usage(plugin);
     return -1;
  }
 }
...


The elemcounter state is deallocated using the bgpcorsaro_elemcounter_close_output function.

/* in int bgpcorsaro_elemcounter_close_output(bgpcorsaro_t *bgpcorsaro) */
 ... 
if(state != NULL)
 {
  /* deallocate dynamic memory in state:
   * elemcounter does not have any dynamic memory variable
   * so no free is required  */
  bgpcorsaro_plugin_free_state(bgpcorsaro->plugin_manager,  PLUGIN(bgpcorsaro));
 }
...


elemcounter start interval, end interval and process record

At the beginning of each interval, we reset the counters.

int bgpcorsaro_elemcounter_start_interval(bgpcorsaro_t *bgpcorsaro,
                                          bgpcorsaro_interval_t *int_start)
{
  struct bgpcorsaro_elemcounter_state_t *state = STATE(bgpcorsaro);
  int i;
  /* reset counters */
  for(i=0; i< 5; i++)
    {
      state->elem_cnt[i] = 0;
    }
  return 0;
}


Each time bgpcorsaro provides a new BGP Stream record to process, we extract the BGP Stream elems that it contains, and we increment the counters.

int bgpcorsaro_elemcounter_process_record(bgpcorsaro_t *bgpcorsaro,
                                          bgpcorsaro_record_t *record)
{
  struct bgpcorsaro_elemcounter_state_t *state = STATE(bgpcorsaro);
  bgpstream_record_t *bs_record = BS_REC(record);
  bgpstream_elem_t *elem;

  /* consider only valid records */
  if(bs_record->status != BGPSTREAM_RECORD_STATUS_VALID_RECORD)
    {
      return 0;
    }

  while((elem = bgpstream_record_get_next_elem(bs_record)) != NULL)
    {
     /* increment the specific type counter */
     state->elem_cnt[elem->type]++;
     }
return 0;
}


At the end of the interval we output the counters using the format specified from command line.

int bgpcorsaro_elemcounter_end_interval(bgpcorsaro_t *bgpcorsaro,
                                        bgpcorsaro_interval_t *int_end)
{
  struct bgpcorsaro_elemcounter_state_t *state = STATE(bgpcorsaro);

  /* int_end->time is a uint32_t time in epoch */

  /* single line output */
  if(state->multiline_flag == 0)
    {
      printf("%"PRIu32" R: %d A: %d W: %d S: %d\n", int_end->time,
             state->elem_cnt[BGPSTREAM_ELEM_TYPE_RIB],
             state->elem_cnt[BGPSTREAM_ELEM_TYPE_ANNOUNCEMENT],
             state->elem_cnt[BGPSTREAM_ELEM_TYPE_WITHDRAWAL],
             state->elem_cnt[BGPSTREAM_ELEM_TYPE_PEERSTATE]);
    }
  else
    { /* multi line output */
      printf("%"PRIu32" R: %d\n", int_end->time,
             state->elem_cnt[BGPSTREAM_ELEM_TYPE_RIB]);
      printf("%"PRIu32" A: %d\n", int_end->time,
             state->elem_cnt[BGPSTREAM_ELEM_TYPE_ANNOUNCEMENT]);
      printf("%"PRIu32" W: %d\n", int_end->time,
             state->elem_cnt[BGPSTREAM_ELEM_TYPE_WITHDRAWAL]);
      printf("%"PRIu32" S: %d\n", int_end->time,
             state->elem_cnt[BGPSTREAM_ELEM_TYPE_PEERSTATE]);
    }
  return 0;
}


Complete example

The complete example is available for (download).

/*
 * This file is part of bgpstream
 *
 * CAIDA, UC San Diego
 * bgpstream-info@caida.org
 *
 * Copyright (C) 2012 The Regents of the University of California.
 * Authors: Alistair King, Chiara Orsini
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "config.h"
#include "bgpcorsaro_int.h"

#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "utils.h"
#include "wandio_utils.h"

#include "bgpcorsaro_io.h"
#include "bgpcorsaro_log.h"
#include "bgpcorsaro_plugin.h"

#include "bgpcorsaro_elemcounter.h"

/** @file
 *
 * @brief Bgpcorsaro Elem Counter plugin implementation
 *
 * @author Chiara Orsini
 *
 */

/** The name of this plugin */
#define PLUGIN_NAME "elemcounter"

/** The version of this plugin */
#define PLUGIN_VERSION "0.1"

/** Common plugin information across all instances */
static bgpcorsaro_plugin_t bgpcorsaro_elemcounter_plugin = {
  PLUGIN_NAME,                                  /* name */
  PLUGIN_VERSION,                               /* version */
  BGPCORSARO_PLUGIN_ID_ELEMCOUNTER,                 /* id */
  BGPCORSARO_PLUGIN_GENERATE_PTRS(bgpcorsaro_elemcounter), /* func ptrs */
  BGPCORSARO_PLUGIN_GENERATE_TAIL,
};


/** Holds the state for an instance of this plugin */
struct bgpcorsaro_elemcounter_state_t {

  /* elem counter array, one counter per 
   * BGPStream elem type*/
  int elem_cnt[5];

  /* 0 if the preferred output is singleline (default)
  *  1 if the preferred output is multiline */
  int multiline_flag;

};


/** Extends the generic plugin state convenience macro in bgpcorsaro_plugin.h */
#define STATE(bgpcorsaro)                        \
  (BGPCORSARO_PLUGIN_STATE(bgpcorsaro, elemcounter, BGPCORSARO_PLUGIN_ID_ELEMCOUNTER))

/** Extends the generic plugin plugin convenience macro in bgpcorsaro_plugin.h */
#define PLUGIN(bgpcorsaro)                        \
  (BGPCORSARO_PLUGIN_PLUGIN(bgpcorsaro, BGPCORSARO_PLUGIN_ID_ELEMCOUNTER))

/** Print usage information to stderr */
static void usage(bgpcorsaro_plugin_t *plugin)
{
  fprintf(stderr,
      "plugin usage: %s [-m]\n"
          "       -m multiline output  (default: singleline)\n",
      plugin->argv[0]);
}

/** Parse the arguments given to the plugin */
static int parse_args(bgpcorsaro_t *bgpcorsaro)
{
  bgpcorsaro_plugin_t *plugin = PLUGIN(bgpcorsaro);
  struct bgpcorsaro_elemcounter_state_t *state = STATE(bgpcorsaro);

  int opt;

  if(plugin->argc <= 0)
    {
      return 0;
    }

  /* NB: remember to reset optind to 1 before using getopt! */
  optind = 1;

  while((opt = getopt(plugin->argc, plugin->argv, ":m?")) >= 0)
    {
      switch(opt)
    {
        case 'm':
      state->multiline_flag = 1;
      break;
    case '?':
    case ':':
    default:
      usage(plugin);
      return -1;
    }
    }

  return 0;
}




/* == PUBLIC PLUGIN FUNCS BELOW HERE == */

/** Implements the alloc function of the plugin API */
bgpcorsaro_plugin_t *bgpcorsaro_elemcounter_alloc(bgpcorsaro_t *bgpcorsaro)
{
  return &bgpcorsaro_elemcounter_plugin;
}

/** Implements the init_output function of the plugin API */
int bgpcorsaro_elemcounter_init_output(bgpcorsaro_t *bgpcorsaro)
{
  struct bgpcorsaro_elemcounter_state_t *state;
  bgpcorsaro_plugin_t *plugin = PLUGIN(bgpcorsaro);
  assert(plugin != NULL);

  if((state = malloc_zero(sizeof(struct bgpcorsaro_elemcounter_state_t))) == NULL)
    {
      bgpcorsaro_log(__func__, bgpcorsaro,
             "could not malloc bgpcorsaro_elemcounter_state_t");
      goto err;
    }
  bgpcorsaro_plugin_register_state(bgpcorsaro->plugin_manager, plugin, state);

  /* allocate memory for state variables:
   * elemcounter does not have any dynamic memory variable
   * so no malloc is required */

  /* initialize state variables */
  int i;
  for(i=0; i< 5; i++)
    {
      state->elem_cnt[i] = 0;
    }

  /* single line is the default output format */
  state->multiline_flag = 0;

  /* parse the arguments */
  if(parse_args(bgpcorsaro) != 0)
    {
      return -1;
    }

  return 0;

 err:
  bgpcorsaro_elemcounter_close_output(bgpcorsaro);
  return -1;
}

/** Implements the close_output function of the plugin API */
int bgpcorsaro_elemcounter_close_output(bgpcorsaro_t *bgpcorsaro)
{

  struct bgpcorsaro_elemcounter_state_t *state = STATE(bgpcorsaro);

  if(state != NULL)
    {

      /* deallocate dynamic memory in state:
       * elemcounter does not have any dynamic memory variable
       * so no free is required  */

      bgpcorsaro_plugin_free_state(bgpcorsaro->plugin_manager, PLUGIN(bgpcorsaro));
    }
  return 0;
}

/** Implements the start_interval function of the plugin API */
int bgpcorsaro_elemcounter_start_interval(bgpcorsaro_t *bgpcorsaro,
                                          bgpcorsaro_interval_t *int_start)
{
  struct bgpcorsaro_elemcounter_state_t *state = STATE(bgpcorsaro);
  int i;
  /* reset counters */
  for(i=0; i< 5; i++)
    {
      state->elem_cnt[i] = 0;
    }
  return 0;
}

/** Implements the end_interval function of the plugin API */
int bgpcorsaro_elemcounter_end_interval(bgpcorsaro_t *bgpcorsaro,
                                        bgpcorsaro_interval_t *int_end)
{
  struct bgpcorsaro_elemcounter_state_t *state = STATE(bgpcorsaro);

  /* int_end->time is a uint32_t time in epoch */

  /* single line output */
  if(state->multiline_flag == 0)
    {
      printf("%"PRIu32" R: %d A: %d W: %d S: %d\n", int_end->time,
             state->elem_cnt[BGPSTREAM_ELEM_TYPE_RIB],
             state->elem_cnt[BGPSTREAM_ELEM_TYPE_ANNOUNCEMENT],
             state->elem_cnt[BGPSTREAM_ELEM_TYPE_WITHDRAWAL],
             state->elem_cnt[BGPSTREAM_ELEM_TYPE_PEERSTATE]);
    }
  else
    { /* multi line output */
      printf("%"PRIu32" R: %d\n", int_end->time,
             state->elem_cnt[BGPSTREAM_ELEM_TYPE_RIB]);
      printf("%"PRIu32" A: %d\n", int_end->time,
             state->elem_cnt[BGPSTREAM_ELEM_TYPE_ANNOUNCEMENT]);
      printf("%"PRIu32" W: %d\n", int_end->time,
             state->elem_cnt[BGPSTREAM_ELEM_TYPE_WITHDRAWAL]);
      printf("%"PRIu32" S: %d\n", int_end->time,
             state->elem_cnt[BGPSTREAM_ELEM_TYPE_PEERSTATE]);
    }
  return 0;
}

/** Implements the process_record function of the plugin API */
int bgpcorsaro_elemcounter_process_record(bgpcorsaro_t *bgpcorsaro,
                                          bgpcorsaro_record_t *record)
{
  struct bgpcorsaro_elemcounter_state_t *state = STATE(bgpcorsaro);
  bgpstream_record_t *bs_record = BS_REC(record);
  bgpstream_elem_t *elem;

  /* consider only valid records */
  if(bs_record->status != BGPSTREAM_RECORD_STATUS_VALID_RECORD)
    {
      return 0;
    }
  while((elem = bgpstream_record_get_next_elem(bs_record)) != NULL)
    {
      /* increment the specific type counter */
      state->elem_cnt[elem->type]++;
    }
return 0;
}


Compile and run

To compile the elemcounter plugin, use:

$ make
$ make install


Here we show how to run elemcounter on the stream of RIBs and Updates of Route Views Singapore for an hour, specifing the multiline format, using an interval size of 5 seconds.

$ bgpcorsaro -w1420070395,1420073995 -c route-views.sg -i 1 -x"elemcounter -m " -O./%X.txt
1420070399 R: 0
1420070399 A: 65
1420070399 W: 6
1420070399 S: 0
1420070404 R: 1127127
1420070404 A: 23
1420070404 W: 5
1420070404 S: 0
...


There are 65 announcements, and 6 withdrawals observed in the first interval, 1,127,127 RIB entries, 23 announcements, and 5 withdrawals in the second interval.