/* Try to get next flow, which should succeed */ static void test_flow_table_get_next_flow(int argc, char *argv[]) { struct flow_key key1 = {1}; struct flow_key key2 = {2}; struct flow_key key_check = {0}; struct action action_multiple[MAX_ACTIONS] = {0}; struct action action_check[MAX_ACTIONS] = {0}; struct flow_stats stats_zero = {0}; struct flow_stats stats_check = {0}; int ret = 0; flow_table_init(); flow_table_del_all(); action_output_build(&action_multiple[0], 1); action_null_build(&action_multiple[1]); ret = flow_table_add_flow(&key1, action_multiple); assert(ret >= 0); ret = flow_table_add_flow(&key2, action_multiple); assert(ret >= 0); ret = flow_table_get_first_flow(&key_check, action_check, &stats_check); assert(ret >= 0); if (memcmp(&key1, &key_check, sizeof(struct flow_key)) == 0 ) { ret = flow_table_get_next_flow(&key_check, &key_check, action_check, &stats_check); assert(ret >= 0); assert(memcmp(action_multiple, action_check, sizeof(struct action)) == 0); assert(memcmp(&stats_zero, &stats_check, sizeof(struct flow_stats)) == 0 ); assert(memcmp(&key2, &key_check, sizeof(struct flow_key)) == 0 ); } else if (memcmp(&key2, &key_check, sizeof(struct flow_key) == 0)) { ret = flow_table_get_next_flow(&key_check, &key_check, action_check, &stats_check); assert(ret >= 0); assert(memcmp(action_multiple, action_check, sizeof(struct action)) == 0); assert(memcmp(&stats_zero, &stats_check, sizeof(struct flow_stats)) == 0 ); assert(memcmp(&key1, &key_check, sizeof(struct flow_key)) == 0 ); } else { assert(1==0); } }
/* Try to delete a normal flow and a non-existent flow, which should succeed * and fail with -1 respectively */ static void test_flow_table_del_flow(int argc, char *argv[]) { struct flow_key key1 = {1}; struct action action_multiple[MAX_ACTIONS] = {0}; int ret = 0; flow_table_init(); /* TODO: Break this into multiple tests? */ action_output_build(&action_multiple[0], 1); action_output_build(&action_multiple[1], 2); action_null_build(&action_multiple[2]); flow_table_add_flow(&key1, action_multiple); ret = flow_table_del_flow(&key1); assert(ret >= 0); /* check no flow match */ ret = flow_table_get_flow(&key1, NULL, NULL); assert(ret < 0); ret = flow_table_del_flow(&key1); assert(ret < 0); }
/* Try to get a flow, which should succeed */ static void test_flow_table_get_flow(int argc, char *argv[]) { struct flow_key key1 = {1}; struct action action_multiple[MAX_ACTIONS] = {0}; struct action action_check[MAX_ACTIONS] = {0}; struct flow_stats stats_zero = {0}; struct flow_stats stats_check = {0}; int ret = 0; flow_table_init(); action_output_build(&action_multiple[0], 1); action_output_build(&action_multiple[1], 2); action_null_build(&action_multiple[2]); flow_table_add_flow(&key1, action_multiple); ret = flow_table_get_flow(&key1, action_check, &stats_check); assert(ret >= 0); assert(memcmp(&action_multiple[0], action_check, sizeof(struct action)) == 0); assert(memcmp(&action_multiple[1], &action_check[1], sizeof(struct action)) == 0); assert(memcmp(&stats_zero, &stats_check , sizeof(struct flow_stats)) == 0 ); }
int main(int argc, char *argv[]) { if (argc < 2) { fprintf(stderr, "Usage: %s <interface> [whitelist]\n", argv[0]); return 1; } struct timeval start_timeval; gettimeofday(&start_timeval, NULL); start_timestamp_microseconds = start_timeval.tv_sec * NUM_MICROS_PER_SECOND + start_timeval.tv_usec; if (initialize_bismark_id()) { return 1; } if (argc < 3 || initialize_domain_whitelist(argv[2])) { fprintf(stderr, "Error loading domain whitelist; whitelisting disabled.\n"); } #ifndef DISABLE_ANONYMIZATION if (anonymization_init()) { fprintf(stderr, "Error initializing anonymizer\n"); return 1; } #endif packet_series_init(&packet_data); flow_table_init(&flow_table); dns_table_init(&dns_table, &domain_whitelist); address_table_init(&address_table); drop_statistics_init(&drop_statistics); #ifdef ENABLE_FREQUENT_UPDATES device_throughput_table_init(&device_throughput_table); #endif if (pthread_mutex_init(&update_lock, NULL)) { perror("Error initializing mutex"); return 1; } sigset_t signal_set; sigemptyset(&signal_set); sigaddset(&signal_set, SIGINT); sigaddset(&signal_set, SIGTERM); if (pthread_sigmask(SIG_BLOCK, &signal_set, NULL)) { perror("Error calling pthread_sigmask"); return 1; } if (pthread_create(&signal_thread, NULL, handle_signals, &signal_set)) { perror("Error creating signal handling thread"); return 1; } if (pthread_create(&update_thread, NULL, updater, NULL)) { perror("Error creating updates thread"); return 1; } #ifdef ENABLE_FREQUENT_UPDATES if (pthread_create(&frequent_update_thread, NULL, frequent_updater, NULL)) { perror("Error creating frequent updates thread"); return 1; } #endif /* By default, pcap uses an internal buffer of 500 KB. Any packets that * overflow this buffer will be dropped. pcap_stats tells the number of * dropped packets. * * Because pcap does its own buffering, we don't need to run packet * processing in a separate thread. (It would be easier to just increase * the buffer size if we experience performance problems.) */ pcap_handle = initialize_pcap(argv[1]); if (!pcap_handle) { return 1; } return pcap_loop(pcap_handle, -1, process_packet, NULL); }