iow_t *bgpcorsaro_io_prepare_file_full(bgpcorsaro_t *bgpcorsaro, const char *plugin_name, bgpcorsaro_interval_t *interval, int compress_type, int compress_level, int flags) { iow_t *f = NULL; char *outfileuri; /* generate a file name based on the plugin name */ if ((outfileuri = generate_file_name(bgpcorsaro, plugin_name, interval, compress_type)) == NULL) { bgpcorsaro_log(__func__, bgpcorsaro, "could not generate file name for %s", plugin_name); return NULL; } if ((f = wandio_wcreate(outfileuri, compress_type, compress_level, flags)) == NULL) { bgpcorsaro_log(__func__, bgpcorsaro, "could not open %s for writing", outfileuri); return NULL; } free(outfileuri); return f; }
/** Implements the init_output function of the plugin API */ int bgpcorsaro_pfxmonitor_init_output(bgpcorsaro_t *bgpcorsaro) { struct bgpcorsaro_pfxmonitor_state_t *state; bgpcorsaro_plugin_t *plugin = PLUGIN(bgpcorsaro); assert(plugin != NULL); if ((state = malloc_zero(sizeof(struct bgpcorsaro_pfxmonitor_state_t))) == NULL) { bgpcorsaro_log(__func__, bgpcorsaro, "could not malloc bgpcorsaro_pfxmonitor_state_t"); goto err; } bgpcorsaro_plugin_register_state(bgpcorsaro->plugin_manager, plugin, state); /* initialize state with default values */ state = STATE(bgpcorsaro); strncpy(state->metric_prefix, PFXMONITOR_DEFAULT_METRIC_PFX, PFXMONITOR_METRIC_PFX_LEN); strncpy(state->ip_space_name, PFXMONITOR_DEFAULT_IPSPACE_NAME, PFXMONITOR_METRIC_PFX_LEN); if ((state->poi = bgpstream_ip_counter_create()) == NULL) { goto err; } state->peer_asns_th = PFXMONITOR_DEFAULT_PEER_ASNS_THRESHOLD; state->more_specific = 0; /* parse the arguments */ if (parse_args(bgpcorsaro) != 0) { goto err; } graphite_safe(state->metric_prefix); graphite_safe(state->ip_space_name); /* create all the sets and maps we need */ if ((state->overlapping_pfx_cache = bgpstream_pfx_storage_set_create()) == NULL || (state->non_overlapping_pfx_cache = bgpstream_pfx_storage_set_create()) == NULL || (state->pfx_info = kh_init(pfx_info_map)) == NULL || (state->unique_origins = bgpstream_id_set_create()) == NULL || (state->peer_asns = bgpstream_id_set_create()) == NULL) { goto err; } /* defer opening the output file until we start the first interval */ return 0; err: bgpcorsaro_pfxmonitor_close_output(bgpcorsaro); return -1; }
/** Implements the start_interval function of the plugin API */ int bgpcorsaro_pacifier_start_interval(bgpcorsaro_t *bgpcorsaro, bgpcorsaro_interval_t *int_start) { struct bgpcorsaro_pacifier_state_t *state = STATE(bgpcorsaro); if(state->outfile == NULL) { if(( state->outfile_p[state->outfile_n] = bgpcorsaro_io_prepare_file(bgpcorsaro, PLUGIN(bgpcorsaro)->name, int_start)) == NULL) { bgpcorsaro_log(__func__, bgpcorsaro, "could not open %s output file", PLUGIN(bgpcorsaro)->name); return -1; } state->outfile = state-> outfile_p[state->outfile_n]; } bgpcorsaro_io_write_interval_start(bgpcorsaro, state->outfile, int_start); struct timeval tv; if(state->tv_start == 0) { gettimeofday_wrap(&tv); state->tv_start = tv.tv_sec; state->tv_first_time = state->tv_start; } // a new interval is starting state->intervals++; // fprintf(stderr, "START INTERVAL TIME: %d \n", state->tv_start); return 0; }
/** Implements the start_interval function of the plugin API */ int bgpcorsaro_pfxmonitor_start_interval(bgpcorsaro_t *bgpcorsaro, bgpcorsaro_interval_t *int_start) { struct bgpcorsaro_pfxmonitor_state_t *state = STATE(bgpcorsaro); /* open an output file */ if (state->outfile == NULL) { if ((state->outfile_p[state->outfile_n] = bgpcorsaro_io_prepare_file( bgpcorsaro, PLUGIN(bgpcorsaro)->name, int_start)) == NULL) { bgpcorsaro_log(__func__, bgpcorsaro, "could not open %s output file", PLUGIN(bgpcorsaro)->name); return -1; } state->outfile = state->outfile_p[state->outfile_n]; } bgpcorsaro_io_write_interval_start(bgpcorsaro, state->outfile, int_start); /* save the interval start to correctly output the time series values */ state->interval_start = int_start->time; return 0; }
/** Implements the init_output function of the plugin API */ int bgpcorsaro_pacifier_init_output(bgpcorsaro_t *bgpcorsaro) { struct bgpcorsaro_pacifier_state_t *state; bgpcorsaro_plugin_t *plugin = PLUGIN(bgpcorsaro); assert(plugin != NULL); if((state = malloc_zero(sizeof(struct bgpcorsaro_pacifier_state_t))) == NULL) { bgpcorsaro_log(__func__, bgpcorsaro, "could not malloc bgpcorsaro_pacifier_state_t"); goto err; } bgpcorsaro_plugin_register_state(bgpcorsaro->plugin_manager, plugin, state); // initializing state state = STATE(bgpcorsaro); state->tv_start = 0; // 0 means it is the first interval, so the time has to be initialized at interval start state->wait = 30; // 30 seconds is the default wait time, between start and end state->tv_first_time = 0; // 0 means it is the first interval, so the time has to be initialized at interval start state->intervals = 0; // number of intervals processed state->adaptive = 0; // default behavior is not adaptive /* parse the arguments */ if(parse_args(bgpcorsaro) != 0) { return -1; } /* defer opening the output file until we start the first interval */ return 0; err: bgpcorsaro_pacifier_close_output(bgpcorsaro); return -1; }
/** Entry point for the Bgpcorsaro tool */ int main(int argc, char *argv[]) { /* we MUST not use any of the getopt global vars outside of arg parsing */ /* this is because the plugins can use get opt to parse their config */ int opt; int prevoptind; char *tmpl = NULL; char *name = NULL; int i = 0; int interval = -1000; double this_time = 0; double last_time = 0; char *plugins[BGPCORSARO_PLUGIN_ID_MAX]; int plugin_cnt = 0; char *plugin_arg_ptr = NULL; int align = 0; int rotate = 0; int meta_rotate = -1; int logfile_disable = 0; bgpstream_data_interface_option_t *option; char *projects[PROJECT_CMD_CNT]; int projects_cnt = 0; char *types[TYPE_CMD_CNT]; int types_cnt = 0; char *collectors[COLLECTOR_CMD_CNT]; int collectors_cnt = 0; char *endp; struct window windows[WINDOW_CMD_CNT]; int windows_cnt = 0; char *peerasns[PEERASN_CMD_CNT]; int peerasns_cnt = 0; char *prefixes[PREFIX_CMD_CNT]; int prefixes_cnt = 0; char *communities[COMMUNITY_CMD_CNT]; int communities_cnt = 0; char *interface_options[OPTION_CMD_CNT]; int interface_options_cnt = 0; int rib_period = 0; int live = 0; int rc = 0; signal(SIGINT, catch_sigint); if((stream = bgpstream_create()) == NULL) { fprintf(stderr, "ERROR: Could not create BGPStream instance\n"); return -1; } datasource_id_default = datasource_id = bgpstream_get_data_interface_id(stream); datasource_info = bgpstream_get_data_interface_info(stream, datasource_id); assert(datasource_id != 0); while(prevoptind = optind, (opt = getopt(argc, argv, ":d:o:p:c:t:w:j:k:y:P:i:ag:lLx:n:O:r:R:hv?")) >= 0) { if (optind == prevoptind + 2 && (optarg == NULL || *optarg == '-') ) { opt = ':'; -- optind; } switch(opt) { case 'd': if((datasource_id = bgpstream_get_data_interface_id_by_name(stream, optarg)) == 0) { fprintf(stderr, "ERROR: Invalid data interface name '%s'\n", optarg); usage(); exit(-1); } datasource_info = bgpstream_get_data_interface_info(stream, datasource_id); break; case 'p': if(projects_cnt == PROJECT_CMD_CNT) { fprintf(stderr, "ERROR: A maximum of %d projects can be specified on " "the command line\n", PROJECT_CMD_CNT); usage(); exit(-1); } projects[projects_cnt++] = strdup(optarg); break; case 'c': if(collectors_cnt == COLLECTOR_CMD_CNT) { fprintf(stderr, "ERROR: A maximum of %d collectors can be specified on " "the command line\n", COLLECTOR_CMD_CNT); usage(); exit(-1); } collectors[collectors_cnt++] = strdup(optarg); break; case 't': if(types_cnt == TYPE_CMD_CNT) { fprintf(stderr, "ERROR: A maximum of %d types can be specified on " "the command line\n", TYPE_CMD_CNT); usage(); exit(-1); } types[types_cnt++] = strdup(optarg); break; case 'w': if(windows_cnt == WINDOW_CMD_CNT) { fprintf(stderr, "ERROR: A maximum of %d windows can be specified on " "the command line\n", WINDOW_CMD_CNT); usage(); exit(-1); } /* split the window into a start and end */ if((endp = strchr(optarg, ',')) == NULL) { windows[windows_cnt].end = BGPSTREAM_FOREVER; } else { *endp = '\0'; endp++; windows[windows_cnt].end = atoi(endp); } windows[windows_cnt].start = atoi(optarg); windows_cnt++; break; case 'j': if(peerasns_cnt == PEERASN_CMD_CNT) { fprintf(stderr, "ERROR: A maximum of %d peer asns can be specified on " "the command line\n", PEERASN_CMD_CNT); usage(); exit(-1); } peerasns[peerasns_cnt++] = strdup(optarg); break; case 'k': if(prefixes_cnt == PREFIX_CMD_CNT) { fprintf(stderr, "ERROR: A maximum of %d peer asns can be specified on " "the command line\n", PREFIX_CMD_CNT); usage(); exit(-1); } prefixes[prefixes_cnt++] = strdup(optarg); break; case 'y': if(communities_cnt == COMMUNITY_CMD_CNT) { fprintf(stderr, "ERROR: A maximum of %d communities can be specified on " "the command line\n", PREFIX_CMD_CNT); usage(); exit(-1); } communities[communities_cnt++] = strdup(optarg); break; case 'o': if(interface_options_cnt == OPTION_CMD_CNT) { fprintf(stderr, "ERROR: A maximum of %d interface options can be specified\n", OPTION_CMD_CNT); usage(); exit(-1); } interface_options[interface_options_cnt++] = strdup(optarg); break; case 'P': rib_period = atoi(optarg); break; case 'l': live = 1; break; case 'g': gap_limit = atoi(optarg); break; case 'a': align = 1; break; case 'i': interval = atoi(optarg); break; case 'L': logfile_disable = 1; break; case 'n': name = strdup(optarg); break; case 'O': tmpl = strdup(optarg); break; case 'x': plugins[plugin_cnt++] = strdup(optarg); break; case 'r': rotate = atoi(optarg); break; case 'R': meta_rotate = atoi(optarg); break; case ':': fprintf(stderr, "ERROR: Missing option argument for -%c\n", optopt); usage(); exit(-1); break; case '?': case 'v': fprintf(stderr, "bgpcorsaro version %d.%d.%d\n", BGPSTREAM_MAJOR_VERSION, BGPSTREAM_MID_VERSION, BGPSTREAM_MINOR_VERSION); usage(); exit(0); break; default: usage(); exit(-1); } } /* store the value of the last index*/ /*lastopt = optind;*/ /* reset getopt for others */ optind = 1; /* -- call NO library functions which may use getopt before here -- */ /* this ESPECIALLY means bgpcorsaro_enable_plugin */ for(i=0; i<interface_options_cnt; i++) { if(*interface_options[i] == '?') { dump_if_options(); usage(); exit(0); } else { /* actually set this option */ if((endp = strchr(interface_options[i], ',')) == NULL) { fprintf(stderr, "ERROR: Malformed data interface option (%s)\n", interface_options[i]); fprintf(stderr, "ERROR: Expecting <option-name>,<option-value>\n"); usage(); exit(-1); } *endp = '\0'; endp++; if((option = bgpstream_get_data_interface_option_by_name(stream, datasource_id, interface_options[i])) == NULL) { fprintf(stderr, "ERROR: Invalid option '%s' for data interface '%s'\n", interface_options[i], datasource_info->name); usage(); exit(-1); } bgpstream_set_data_interface_option(stream, option, endp); } free(interface_options[i]); interface_options[i] = NULL; } interface_options_cnt = 0; if(windows_cnt == 0) { fprintf(stderr, "ERROR: At least one time window must be specified using -w\n"); usage(); goto err; } if(tmpl == NULL) { fprintf(stderr, "ERROR: An output file template must be specified using -O\n"); usage(); goto err; } /* alloc bgpcorsaro */ if((bgpcorsaro = bgpcorsaro_alloc_output(tmpl)) == NULL) { usage(); goto err; } if(name != NULL && bgpcorsaro_set_monitorname(bgpcorsaro, name) != 0) { bgpcorsaro_log(__func__, bgpcorsaro, "failed to set monitor name"); goto err; } if(interval > -1000) { bgpcorsaro_set_interval(bgpcorsaro, interval); } if(align == 1) { bgpcorsaro_set_interval_alignment(bgpcorsaro, BGPCORSARO_INTERVAL_ALIGN_YES); } if(rotate > 0) { bgpcorsaro_set_output_rotation(bgpcorsaro, rotate); } if(meta_rotate >= 0) { bgpcorsaro_set_meta_output_rotation(bgpcorsaro, meta_rotate); } for(i=0;i<plugin_cnt;i++) { /* the string at plugins[i] will contain the name of the plugin, optionally followed by a space and then the arguments to pass to the plugin */ if((plugin_arg_ptr = strchr(plugins[i], ' ')) != NULL) { /* set the space to a nul, which allows plugins[i] to be used for the plugin name, and then increment plugin_arg_ptr to point to the next character, which will be the start of the arg string (or at worst case, the terminating \0 */ *plugin_arg_ptr = '\0'; plugin_arg_ptr++; } if(bgpcorsaro_enable_plugin(bgpcorsaro, plugins[i], plugin_arg_ptr) != 0) { fprintf(stderr, "ERROR: Could not enable plugin %s\n", plugins[i]); usage(); goto err; } } if(logfile_disable != 0) { bgpcorsaro_disable_logfile(bgpcorsaro); } if(bgpcorsaro_start_output(bgpcorsaro) != 0) { usage(); goto err; } /* create a record buffer */ if (record == NULL && (record = bgpstream_record_create()) == NULL) { fprintf(stderr, "ERROR: Could not create BGPStream record\n"); return -1; } /* pass along the user's filter requests to bgpstream */ /* types */ for(i=0; i<types_cnt; i++) { bgpstream_add_filter(stream, BGPSTREAM_FILTER_TYPE_RECORD_TYPE, types[i]); free(types[i]); } /* projects */ for(i=0; i<projects_cnt; i++) { bgpstream_add_filter(stream, BGPSTREAM_FILTER_TYPE_PROJECT, projects[i]); free(projects[i]); } /* collectors */ for(i=0; i<collectors_cnt; i++) { bgpstream_add_filter(stream, BGPSTREAM_FILTER_TYPE_COLLECTOR, collectors[i]); free(collectors[i]); } /* windows */ int minimum_time = 0; int current_time = 0; for(i=0; i<windows_cnt; i++) { bgpstream_add_interval_filter(stream, windows[i].start, windows[i].end); current_time = windows[i].start; if(minimum_time == 0 || current_time < minimum_time) { minimum_time = current_time; } } /* peer asns */ for(i=0; i<peerasns_cnt; i++) { bgpstream_add_filter(stream, BGPSTREAM_FILTER_TYPE_ELEM_PEER_ASN, peerasns[i]); free(peerasns[i]); } /* prefixes */ for(i=0; i<prefixes_cnt; i++) { bgpstream_add_filter(stream, BGPSTREAM_FILTER_TYPE_ELEM_PREFIX, prefixes[i]); free(prefixes[i]); } /* communities */ for(i=0; i<communities_cnt; i++) { bgpstream_add_filter(stream, BGPSTREAM_FILTER_TYPE_ELEM_COMMUNITY, communities[i]); free(communities[i]); } /* frequencies */ if(rib_period > 0) { bgpstream_add_rib_period_filter(stream, rib_period); } /* live mode */ if(live != 0) { bgpstream_set_live_mode(stream); } bgpstream_set_data_interface(stream, datasource_id); if(bgpstream_start(stream) < 0) { fprintf(stderr, "ERROR: Could not init BGPStream\n"); return -1; } /* let bgpcorsaro have the trace pointer */ bgpcorsaro_set_stream(bgpcorsaro, stream); while (bgpcorsaro_shutdown == 0 && (rc = bgpstream_get_next_record(stream, record)) > 0 ) { /* remove records that preceed the beginning of the stream */ if(record->attributes.record_time < minimum_time) { continue; } /* check the gap limit is not exceeded */ this_time = record->attributes.record_time; if(gap_limit > 0 && /* gap limit is enabled */ last_time > 0 && /* this is not the first packet */ ((this_time-last_time) > 0) && /* packet doesn't go backward */ (this_time - last_time) > gap_limit) /* packet exceeds gap */ { bgpcorsaro_log(__func__, bgpcorsaro, "gap limit exceeded (prev: %f this: %f diff: %f)", last_time, this_time, (this_time - last_time)); return -1; } last_time = this_time; /*bgpcorsaro_log(__func__, bgpcorsaro, "got a record!");*/ if(bgpcorsaro_per_record(bgpcorsaro, record) != 0) { bgpcorsaro_log(__func__, bgpcorsaro, "bgpcorsaro_per_record failed"); return -1; } } if (rc < 0) { bgpcorsaro_log(__func__, bgpcorsaro, "bgpstream encountered an error processing records"); return 1; } /* free the plugin strings */ for(i=0;i<plugin_cnt;i++) { if(plugins[i] != NULL) free(plugins[i]); } /* free the template string */ if(tmpl != NULL) free(tmpl); bgpcorsaro_finalize_output(bgpcorsaro); bgpcorsaro = NULL; if(stream != NULL) { bgpstream_destroy(stream); stream = NULL; } clean(); return 0; err: /* if we bail early, let us be responsible and up the memory we alloc'd */ for(i=0;i<plugin_cnt;i++) { if(plugins[i] != NULL) free(plugins[i]); } if(tmpl != NULL) free(tmpl); clean(); return -1; }