int collie_exec_req(const char *host, int port, struct sd_req *hdr, void *buf) { struct node_id nid; struct sockfd *sfd; int ret; memset(&nid, 0, sizeof(nid)); str_to_addr(host, nid.addr); nid.port = port; sfd = sockfd_cache_get(&nid); if (!sfd) return -1; /* * Retry forever for collie because * 1. We can't get the newest epoch * 2. Some operations might take unexpected long time */ ret = exec_req(sfd->fd, hdr, buf, NULL, 0, UINT32_MAX); sockfd_cache_put(&nid, sfd); return ret ? -1 : 0; }
/* gethostbyaddr wrapper */ static struct hostent *gethostbyaddr_wrapper(const char *address) { struct in_addr addr; addr.s_addr = str_to_addr(address); return gethostbyaddr((char *) &addr, 4, AF_INET); /* IPv4 only for now */ }
// Parses N(C-S) int parse_test( const struct settings *settings, const char *arg, struct test * test ) { char hostname[NI_MAXHOST + NI_MAXSERV + 1] = {0}; assert( arg != NULL ); assert( test != NULL ); if ( sscanf( arg, "%u(%u-%u:%1000s)", &test->connections, &test->clientcores, &test->servercores, hostname ) == 4 ) { // Find the last ) and remove char *c = strchr(hostname, ')'); if ( c != NULL ) *c = '\0'; goto good; } // Parse with different brackets if ( sscanf( arg, "%u{%u-%u:%1000s}", &test->connections, &test->clientcores, &test->servercores, hostname ) == 4 ) { // Find the last ) and remove char *c = strchr(hostname, '}'); if ( c != NULL ) *c = '\0'; goto good; } // If the hostname hasn't been specified in the test, then use the -H parameter (if that was set) if ( settings->server_host != NULL ) strncpy(hostname, settings->server_host, sizeof(hostname)); if ( sscanf( arg, "%u(%u-%u)", &test->connections, &test->clientcores, &test->servercores ) == 3 ) { goto good; } // Parse with different brackets if ( sscanf( arg, "%u{%u-%u}", &test->connections, &test->clientcores, &test->servercores ) == 3 ) { goto good; } return -1; good: if ( hostname[0] == '\0' ) { strcpy(hostname, "127.0.0.1"); } memset( &test->addr, 0, sizeof(test->addr) ); test->addr_len = sizeof(struct sockaddr_in); if ( str_to_addr( hostname, (struct sockaddr *) &test->addr, &test->addr_len ) ) { fprintf(stderr, "Invalid host name (%s)\n", hostname ); return -1; } ((struct sockaddr_in *)&test->addr)->sin_port = htons( settings->port + test->servercores ); return 0; }
int igp_daemon_map_node_handler(char *filename, struct id_entry *e, char *value, struct plugin_requests *req, int acct_type) { struct igp_map_entry *entry = (struct igp_map_entry *) req->key_value_table; if (!str_to_addr(value, &entry->node) || entry->node.family != AF_INET) { Log(LOG_ERR, "ERROR ( %s ): Bad IPv4 address '%s'. ", filename, value); return TRUE; } return FALSE; }
buffer_t massdns_resolvers_from_file(char *filename) { size_t line_buflen = 4096; char *line = safe_malloc(line_buflen); FILE *f = fopen(filename, "r"); if (f == NULL) { perror("Failed to open resolver file"); exit(1); } single_list_t *list = safe_malloc(sizeof(*list)); list->next = NULL; list->data = NULL; single_list_t *start = list; single_list_t *previous = NULL; while (!feof(f)) { if (0 <= getline(&line, &line_buflen, f)) { trim_end(line); struct sockaddr_in *addr = str_to_addr(line); if (addr != NULL) { list->data = addr; list->next = safe_malloc(sizeof(*list)); previous = list; list = list->next; } else { fprintf(stderr, "\"%s\" is not a valid resolver. Skipped.\n", line); } } else if (previous != NULL) { free(list); list = NULL; previous->next = NULL; } free(line); line = NULL; } fclose(f); buffer_t resolvers = single_list_to_array(start); single_list_iterate(start, free_element, NULL); free(list); return resolvers; }
/* * str_to_addr_mask() converts a string into a supported family address */ unsigned int str_to_addr_mask(const char *str, struct host_addr *a, struct host_mask *m) { char *delim = NULL, *net = NULL, *mask = NULL; unsigned int family = 0, index = 0, j; if (!str || !a || !m) return family; net = (char *) str; delim = strchr(str, '/'); if (delim) { *delim = '\0'; mask = delim+1; } family = str_to_addr(str, a); if (delim) *delim = '/'; if (family) { if (mask) { index = atoi(mask); if (family == AF_INET) { if (index > 32) goto error; else { m->mask.m4 = htonl((index == 32) ? 0xffffffffUL : ~(0xffffffffUL >> index)); a->address.ipv4.s_addr &= m->mask.m4; } } #if defined ENABLE_IPV6 else if (family == AF_INET6) { if (index > 128) goto error; for (j = 0; j < 4 && index >= 32; j++, index -= 32) m->mask.m6[j] = 0xffffffffU; if (j < 4 && index) m->mask.m6[j] = htonl(~(0xffffffffU >> index)); for (j = 0; j < 4; j++) a->address.ipv6.s6_addr[j] &= m->mask.m6[j]; } #endif else goto error; }
int Tee_prepare_sock(struct sockaddr *addr, socklen_t len) { int s, ret = 0; if (!config.tee_transparent) { struct host_addr source_ip; struct sockaddr ssource_ip; if (config.nfprobe_source_ip) { ret = str_to_addr(config.nfprobe_source_ip, &source_ip); addr_to_sa(&ssource_ip, &source_ip, 0); } if ((s = socket(addr->sa_family, SOCK_DGRAM, 0)) == -1) { Log(LOG_ERR, "ERROR ( %s/%s ): socket() error: %s\n", config.name, config.type, strerror(errno)); exit_plugin(1); } if (ret && bind(s, (struct sockaddr *) &ssource_ip, sizeof(ssource_ip)) == -1) Log(LOG_ERR, "ERROR ( %s/%s ): bind() error: %s\n", config.name, config.type, strerror(errno)); } else { if ((s = socket(addr->sa_family, SOCK_RAW, IPPROTO_RAW)) == -1) { Log(LOG_ERR, "ERROR ( %s/%s ): socket() error: %s\n", config.name, config.type, strerror(errno)); exit_plugin(1); } } /* XXX: SNDBUF tuning? */ if (connect(s, (struct sockaddr *)addr, len) == -1) { Log(LOG_ERR, "ERROR ( %s/%s ): connect() error: %s\n", config.name, config.type, strerror(errno)); exit_plugin(1); } return(s); }
int accept_conn(int tcp_list) { int j, rc; int sock_tmp; int nread; unsigned short port; struct sockaddr_in *addr_list; struct sockaddr_in addr; unsigned int len = sizeof(struct sockaddr_in); struct packet send_pck; if ((sock_tmp = accept(tcp_list, (struct sockaddr*)&addr, &len)) < 0) { perror("accept_conn error - accept failed"); return -1; } if (nsock >= max_tcp_sock) { printf("accept_conn - can't accept more connection %s:%u\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); new_err_packet(&send_pck, 0); if (send_packet_tcp(sock_tmp, &send_pck) < 0) { perror("bad write"); return -1; } if (close(sock_tmp) < 0) { perror("accept_conn error - close failed"); return -1; } return 0; } new_ack_packet(&send_pck, 0); if (send_packet_tcp(sock_tmp, &send_pck) < 0) { perror("bad write"); return -1; } if ((nread = read(sock_tmp, (char *)&port, sizeof(port))) != sizeof(port)) { if (nread < 0) { perror("accept_conn error - read failed"); } else { fprintf(stderr, "accept_conn error - bad packet format\n"); } return -1; } printf("connessione accettata da %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); fd_add(sock_tmp); addr.sin_port = port; if ((rc = pthread_mutex_lock(&NEAR_LIST_LOCK)) != 0) { fprintf(stderr, "accept_conn error - can't acquire lock: %s\n", strerror(rc)); return -1; } if (insert_near(sock_tmp, &addr) < 0) { fprintf(stderr, "join_overlay error - insert_near failed\n"); return -1; } set_near(); printf("accept_conn setto la stringa dei vicini\n"); if ((rc = pthread_mutex_unlock(&NEAR_LIST_LOCK)) != 0) { fprintf(stderr, "accept_conn error - can't release lock: %s\n", strerror(rc)); return -1; } addr_list = str_to_addr(near_str, max_tcp_sock); for(j = 0 ; j < max_tcp_sock; j ++){ printf("accept - near %s:%d\n", inet_ntoa(addr_list[j].sin_addr), ntohs(addr_list[j].sin_port)); } nsock ++; return 0; }
int main(int argc, char **argv) { int ch, longindex, ret; unsigned long flags; struct option *long_options; const struct command *commands; const char *short_options; char *p; const struct sd_option *sd_opts; uint8_t sdhost[16]; int sdport; log_dog_operation(argc, argv); install_crash_handler(crash_handler); init_commands(&commands); if (argc < 2) usage(commands, 0); flags = setup_commands(commands, argv[1], argv[2]); optind = 3; sd_opts = build_sd_options(command_opts); long_options = build_long_options(sd_opts); short_options = build_short_options(sd_opts); while ((ch = getopt_long(argc, argv, short_options, long_options, &longindex)) >= 0) { switch (ch) { case 'a': if (!str_to_addr(optarg, sdhost)) { sd_err("Invalid ip address %s", optarg); return EXIT_FAILURE; } memcpy(sd_nid.addr, sdhost, sizeof(sdhost)); break; case 'p': sdport = strtol(optarg, &p, 10); if (optarg == p || sdport < 1 || sdport > UINT16_MAX) { sd_err("Invalid port number '%s'", optarg); exit(EXIT_USAGE); } sd_nid.port = sdport; break; case 'r': raw_output = true; break; case 'v': verbose = true; break; case 'h': subcommand_usage(argv[1], argv[2], EXIT_SUCCESS); break; case '?': usage(commands, EXIT_USAGE); break; default: if (command_parser) command_parser(ch, optarg); else usage(commands, EXIT_USAGE); break; } } if (!is_stdout_console() || raw_output) highlight = false; if (flags & CMD_NEED_NODELIST) { ret = update_node_list(SD_MAX_NODES); if (ret < 0) { sd_err("Failed to get node list"); exit(EXIT_SYSFAIL); } } if (flags & CMD_NEED_ARG && argc == optind) subcommand_usage(argv[1], argv[2], EXIT_USAGE); if (init_event(EPOLL_SIZE) < 0) exit(EXIT_SYSFAIL); if (init_work_queue(get_nr_nodes) != 0) { sd_err("Failed to init work queue"); exit(EXIT_SYSFAIL); } if (sockfd_init()) { sd_err("sockfd_init() failed"); exit(EXIT_SYSFAIL); } ret = command_fn(argc, argv); if (ret == EXIT_USAGE) subcommand_usage(argv[1], argv[2], EXIT_USAGE); return ret; }
int Tee_prepare_sock(struct sockaddr *addr, socklen_t len) { int s, ret = 0; if (!config.tee_transparent) { struct host_addr source_ip; #if defined ENABLE_IPV6 struct sockaddr_storage ssource_ip; #else struct sockaddr ssource_ip; #endif if (config.nfprobe_source_ip) { ret = str_to_addr(config.nfprobe_source_ip, &source_ip); addr_to_sa((struct sockaddr *) &ssource_ip, &source_ip, 0); } if ((s = socket(addr->sa_family, SOCK_DGRAM, 0)) == -1) { Log(LOG_ERR, "ERROR ( %s/%s ): socket() error: %s\n", config.name, config.type, strerror(errno)); exit_plugin(1); } if (config.nfprobe_ipprec) { int opt = config.nfprobe_ipprec << 5; int rc; rc = setsockopt(s, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)); if (rc < 0) Log(LOG_WARNING, "WARN ( %s/%s ): setsockopt() failed for IP_TOS: %s\n", config.name, config.type, strerror(errno)); } if (ret && bind(s, (struct sockaddr *) &ssource_ip, sizeof(ssource_ip)) == -1) Log(LOG_ERR, "ERROR ( %s/%s ): bind() error: %s\n", config.name, config.type, strerror(errno)); } else { int hincl = 1; /* 1 = on, 0 = off */ if ((s = socket(addr->sa_family, SOCK_RAW, IPPROTO_RAW)) == -1) { Log(LOG_ERR, "ERROR ( %s/%s ): socket() error: %s\n", config.name, config.type, strerror(errno)); exit_plugin(1); } #if defined BSD setsockopt(s, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl)); #endif } if (config.tee_pipe_size) { int l = sizeof(config.tee_pipe_size); int saved = 0, obtained = 0; getsockopt(s, SOL_SOCKET, SO_SNDBUF, &saved, &l); Setsocksize(s, SOL_SOCKET, SO_SNDBUF, &config.tee_pipe_size, sizeof(config.tee_pipe_size)); getsockopt(s, SOL_SOCKET, SO_SNDBUF, &obtained, &l); if (obtained < saved) { Setsocksize(s, SOL_SOCKET, SO_SNDBUF, &saved, l); getsockopt(s, SOL_SOCKET, SO_SNDBUF, &obtained, &l); } Log(LOG_INFO, "INFO ( %s/%s ): tee_pipe_size: obtained=%d target=%d.\n", config.name, config.type, obtained, config.tee_pipe_size); } if (connect(s, (struct sockaddr *)addr, len) == -1) { Log(LOG_ERR, "ERROR ( %s/%s ): connect() error: %s\n", config.name, config.type, strerror(errno)); exit_plugin(1); } return(s); }
int main(int argc, char **argv) { int ch, longindex, ret; unsigned long flags; struct option *long_options; const struct command *commands; const char *short_options; char *p, *env; const struct sd_option *sd_opts; uint8_t sdhost[16]; int sdport; struct timespec start, end; start = get_time_tick(); log_dog_operation(argc, argv); install_crash_handler(crash_handler); init_commands(&commands); if (argc < 2) usage(commands, 0); flags = setup_commands(commands, argv[1], argv[2]); optind = 3; sd_opts = build_sd_options(command_opts); long_options = build_long_options(sd_opts); short_options = build_short_options(sd_opts); env = getenv("SHEEPDOG_DOG_ADDR"); if (env) { if (!str_to_addr(env, sdhost)) { sd_err("Invalid ip address %s", env); return EXIT_FAILURE; } memcpy(sd_nid.addr, sdhost, sizeof(sdhost)); } env = getenv("SHEEPDOG_DOG_PORT"); if (env) { sdport = strtol(env, &p, 10); if (env == p || sdport < 1 || sdport > UINT16_MAX || !is_numeric(env)) { sd_err("Invalid port number '%s'", env); exit(EXIT_USAGE); } sd_nid.port = sdport; } while ((ch = getopt_long(argc, argv, short_options, long_options, &longindex)) >= 0) { switch (ch) { case 'a': if (!str_to_addr(optarg, sdhost)) { sd_err("Invalid ip address %s", optarg); return EXIT_FAILURE; } memcpy(sd_nid.addr, sdhost, sizeof(sdhost)); break; case 'p': sdport = strtol(optarg, &p, 10); if (optarg == p || sdport < 1 || sdport > UINT16_MAX || !is_numeric(optarg)) { sd_err("Invalid port number '%s'", optarg); exit(EXIT_USAGE); } sd_nid.port = sdport; break; case 'r': raw_output = true; break; case 'v': verbose = true; break; case 'h': subcommand_usage(argv[1], argv[2], EXIT_SUCCESS); break; case 'T': elapsed_time = true; break; case '?': usage(commands, EXIT_USAGE); break; default: if (command_parser) command_parser(ch, optarg); else usage(commands, EXIT_USAGE); break; } } if (sd_inode_actor_init(dog_bnode_writer, dog_bnode_reader) < 0) exit(EXIT_SYSFAIL); if (!is_stdout_console() || raw_output) highlight = false; if (flags & CMD_NEED_NODELIST) { ret = update_node_list(SD_MAX_NODES); if (ret < 0) { sd_err("Failed to get node list"); exit(EXIT_SYSFAIL); } } if (flags & CMD_NEED_ARG && argc == optind) subcommand_usage(argv[1], argv[2], EXIT_USAGE); if (init_event(EPOLL_SIZE) < 0) exit(EXIT_SYSFAIL); if (wq_trace_init() < 0) exit(EXIT_SYSFAIL); if (init_work_queue(get_nr_nodes) != 0) { sd_err("Failed to init work queue"); exit(EXIT_SYSFAIL); } if (sockfd_init()) { sd_err("sockfd_init() failed"); exit(EXIT_SYSFAIL); } ret = command_fn(argc, argv); if (ret == EXIT_USAGE) subcommand_usage(argv[1], argv[2], EXIT_USAGE); if (elapsed_time) { end = get_time_tick(); printf("\nElapsed time: %.3lf seconds\n", get_time_interval(&start, &end)); } return ret; }
int main(int argc, char **argv) { int ch, longindex, ret, port = SD_LISTEN_PORT, io_port = SD_LISTEN_PORT; int log_level = SDOG_INFO, nr_vnodes = SD_DEFAULT_VNODES; const char *dirp = DEFAULT_OBJECT_DIR, *short_options; char *dir, *p, *pid_file = NULL, *bindaddr = NULL, path[PATH_MAX], *argp = NULL, *logdir = NULL; bool is_daemon = true, to_stdout = false, explicit_addr = false; int64_t zone = -1; struct cluster_driver *cdrv; struct option *long_options; const char *log_format = "server", *http_address = NULL; static struct logger_user_info sheep_info; install_crash_handler(crash_handler); signal(SIGPIPE, SIG_IGN); install_sighandler(SIGHUP, sighup_handler, false); long_options = build_long_options(sheep_options); short_options = build_short_options(sheep_options); while ((ch = getopt_long(argc, argv, short_options, long_options, &longindex)) >= 0) { switch (ch) { case 'p': port = strtol(optarg, &p, 10); if (optarg == p || port < 1 || UINT16_MAX < port || *p != '\0') { sd_err("Invalid port number '%s'", optarg); exit(1); } break; case 'P': pid_file = optarg; break; case 'r': http_address = optarg; break; case 'f': is_daemon = false; break; case 'l': log_level = strtol(optarg, &p, 10); if (optarg == p || log_level < SDOG_EMERG || SDOG_DEBUG < log_level || *p != '\0') { sd_err("Invalid log level '%s'", optarg); sdlog_help(); exit(1); } break; case 'L': logdir = realpath(optarg, NULL); if (!logdir) { sd_err("%m"); exit(1); } break; case 'n': sys->nosync = true; break; case 'y': if (!str_to_addr(optarg, sys->this_node.nid.addr)) { sd_err("Invalid address: '%s'", optarg); exit(1); } explicit_addr = true; break; case 'd': /* removed soon. use loglevel instead */ log_level = SDOG_DEBUG; break; case 'D': sys->backend_dio = true; break; case 'g': /* same as '-v 0' */ //printf("wyh\n"); nr_vnodes = 0; //nr_vnodes = 5; break; case 'o': to_stdout = true; break; case 'z': zone = strtol(optarg, &p, 10); if (optarg == p || zone < 0 || UINT32_MAX < zone || *p != '\0') { sd_err("Invalid zone id '%s': must be " "an integer between 0 and %u", optarg, UINT32_MAX); exit(1); } sys->this_node.zone = zone; break; case 'u': sys->upgrade = true; break; case 'c': sys->cdrv = find_cdrv(optarg); if (!sys->cdrv) { sd_err("Invalid cluster driver '%s'", optarg); fprintf(stderr, "Supported drivers:"); FOR_EACH_CLUSTER_DRIVER(cdrv) { fprintf(stderr, " %s", cdrv->name); } fprintf(stderr, "\n"); exit(1); } sys->cdrv_option = get_cdrv_option(sys->cdrv, optarg); break; case 'w': object_cache_set(optarg); break; case 'i': parse_arg(optarg, ",", init_io_arg); if (!str_to_addr(io_addr, sys->this_node.nid.io_addr)) { sd_err("Bad addr: '%s'", io_addr); exit(1); } if (io_pt) if (sscanf(io_pt, "%u", &io_port) != 1) { sd_err("Bad port '%s'", io_pt); exit(1); } sys->this_node.nid.io_port = io_port; break; case 'j': uatomic_set_true(&sys->use_journal); parse_arg(optarg, ",", init_journal_arg); if (!jsize) { sd_err("you must specify size for journal"); exit(1); } break; case 'b': if (!inetaddr_is_valid(optarg)) exit(1); bindaddr = optarg; break; case 'h': usage(0); break; case 'v': fprintf(stdout, "Sheepdog daemon version %s\n", PACKAGE_VERSION); exit(0); break; case 'F': log_format = optarg; break; default: usage(1); break; } }
void telemetry_daemon(void *t_data_void) { struct telemetry_data *t_data = t_data_void; telemetry_peer_udp_cache tpuc; int slen, clen, ret, rc, peers_idx, allowed, yes=1, no=0; int peers_idx_rr = 0, max_peers_idx = 0, peers_num = 0; int decoder = 0, data_decoder = 0, recv_flags = 0; u_int16_t port = 0; char *srv_proto = NULL; time_t now, last_udp_timeout_check; telemetry_peer *peer = NULL; telemetry_peer_z *peer_z = NULL; #if defined ENABLE_IPV6 struct sockaddr_storage server, client; #else struct sockaddr server, client; #endif struct hosts_table allow; struct host_addr addr; /* select() stuff */ fd_set read_descs, bkp_read_descs; int fd, select_fd, bkp_select_fd, recalc_fds, select_num; /* logdump time management */ time_t dump_refresh_deadline; struct timeval dump_refresh_timeout, *drt_ptr; if (!t_data) { Log(LOG_ERR, "ERROR ( %s/%s ): telemetry_daemon(): missing telemetry data. Terminating.\n", config.name, t_data->log_str); exit_all(1); } /* initial cleanups */ reload_log_telemetry_thread = FALSE; memset(&server, 0, sizeof(server)); memset(&client, 0, sizeof(client)); memset(&allow, 0, sizeof(struct hosts_table)); clen = sizeof(client); telemetry_peers_udp_cache = NULL; last_udp_timeout_check = FALSE; telemetry_misc_db = &inter_domain_misc_dbs[FUNC_TYPE_TELEMETRY]; memset(telemetry_misc_db, 0, sizeof(telemetry_misc_structs)); /* initialize variables */ if (config.telemetry_port_tcp && config.telemetry_port_udp) { Log(LOG_ERR, "ERROR ( %s/%s ): telemetry_daemon_port_tcp and telemetry_daemon_port_udp are mutually exclusive. Terminating.\n", config.name, t_data->log_str); exit_all(1); } else if (!config.telemetry_port_tcp && !config.telemetry_port_udp) { /* defaulting to TCP */ port = config.telemetry_port_tcp = TELEMETRY_TCP_PORT; srv_proto = malloc(strlen("tcp") + 1); strcpy(srv_proto, "tcp"); } else { if (config.telemetry_port_tcp) { port = config.telemetry_port_tcp; srv_proto = malloc(strlen("tcp") + 1); strcpy(srv_proto, "tcp"); } if (config.telemetry_port_udp) { port = config.telemetry_port_udp; srv_proto = malloc(strlen("udp") + 1); strcpy(srv_proto, "udp"); } } /* socket creation for telemetry server: IPv4 only */ #if (defined ENABLE_IPV6) if (!config.telemetry_ip) { struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&server; sa6->sin6_family = AF_INET6; sa6->sin6_port = htons(port); slen = sizeof(struct sockaddr_in6); } #else if (!config.telemetry_ip) { struct sockaddr_in *sa4 = (struct sockaddr_in *)&server; sa4->sin_family = AF_INET; sa4->sin_addr.s_addr = htonl(0); sa4->sin_port = htons(port); slen = sizeof(struct sockaddr_in); } #endif else { trim_spaces(config.telemetry_ip); ret = str_to_addr(config.telemetry_ip, &addr); if (!ret) { Log(LOG_ERR, "ERROR ( %s/%s ): telemetry_daemon_ip value is not a valid IPv4/IPv6 address. Terminating.\n", config.name, t_data->log_str); exit_all(1); } slen = addr_to_sa((struct sockaddr *)&server, &addr, port); } if (!config.telemetry_decoder) { Log(LOG_ERR, "ERROR ( %s/%s ): telemetry_daemon_decoder is not specified. Terminating.\n", config.name, t_data->log_str); exit_all(1); } else { if (!strcmp(config.telemetry_decoder, "json")) decoder = TELEMETRY_DECODER_JSON; else if (!strcmp(config.telemetry_decoder, "zjson")) { #if defined (HAVE_ZLIB) decoder = TELEMETRY_DECODER_ZJSON; #else Log(LOG_ERR, "ERROR ( %s/%s ): telemetry_daemon_decoder set to 'zjson' but zlib not available. Terminating.\n", config.name, t_data->log_str); exit_all(1); #endif } else if (!strcmp(config.telemetry_decoder, "cisco_json")) decoder = TELEMETRY_DECODER_CISCO_JSON; else if (!strcmp(config.telemetry_decoder, "cisco_zjson")) { #if defined (HAVE_ZLIB) decoder = TELEMETRY_DECODER_CISCO_ZJSON; #else Log(LOG_ERR, "ERROR ( %s/%s ): telemetry_daemon_decoder set to 'cisco_zjson' but zlib not available. Terminating.\n", config.name, t_data->log_str); exit_all(1); #endif } else if (!strcmp(config.telemetry_decoder, "cisco")) decoder = TELEMETRY_DECODER_CISCO; else if (!strcmp(config.telemetry_decoder, "cisco_gpb")) decoder = TELEMETRY_DECODER_CISCO_GPB; else if (!strcmp(config.telemetry_decoder, "cisco_gpb_kv")) decoder = TELEMETRY_DECODER_CISCO_GPB_KV; else { Log(LOG_ERR, "ERROR ( %s/%s ): telemetry_daemon_decoder set to unknown value. Terminating.\n", config.name, t_data->log_str); exit_all(1); } } if (!config.telemetry_max_peers) config.telemetry_max_peers = TELEMETRY_MAX_PEERS_DEFAULT; Log(LOG_INFO, "INFO ( %s/%s ): maximum telemetry peers allowed: %d\n", config.name, t_data->log_str, config.telemetry_max_peers); if (config.telemetry_port_udp) { if (!config.telemetry_udp_timeout) config.telemetry_udp_timeout = TELEMETRY_UDP_TIMEOUT_DEFAULT; Log(LOG_INFO, "INFO ( %s/%s ): telemetry UDP peers timeout: %u\n", config.name, t_data->log_str, config.telemetry_udp_timeout); } telemetry_peers = malloc(config.telemetry_max_peers*sizeof(telemetry_peer)); if (!telemetry_peers) { Log(LOG_ERR, "ERROR ( %s/%s ): Unable to malloc() telemetry_peers structure. Terminating.\n", config.name, t_data->log_str); exit_all(1); } memset(telemetry_peers, 0, config.telemetry_max_peers*sizeof(telemetry_peer)); if (telemetry_is_zjson(decoder)) { telemetry_peers_z = malloc(config.telemetry_max_peers*sizeof(telemetry_peer_z)); if (!telemetry_peers_z) { Log(LOG_ERR, "ERROR ( %s/%s ): Unable to malloc() telemetry_peers_z structure. Terminating.\n", config.name, t_data->log_str); exit_all(1); } memset(telemetry_peers_z, 0, config.telemetry_max_peers*sizeof(telemetry_peer_z)); } if (config.telemetry_port_udp) { telemetry_peers_udp_timeout = malloc(config.telemetry_max_peers*sizeof(telemetry_peer_udp_timeout)); if (!telemetry_peers_udp_timeout) { Log(LOG_ERR, "ERROR ( %s/%s ): Unable to malloc() telemetry_peers_udp_timeout structure. Terminating.\n", config.name, t_data->log_str); exit_all(1); } memset(telemetry_peers_udp_timeout, 0, config.telemetry_max_peers*sizeof(telemetry_peer_udp_timeout)); } if (config.telemetry_msglog_file || config.telemetry_msglog_amqp_routing_key || config.telemetry_msglog_kafka_topic) { if (config.telemetry_msglog_file) telemetry_misc_db->msglog_backend_methods++; if (config.telemetry_msglog_amqp_routing_key) telemetry_misc_db->msglog_backend_methods++; if (config.telemetry_msglog_kafka_topic) telemetry_misc_db->msglog_backend_methods++; if (telemetry_misc_db->msglog_backend_methods > 1) { Log(LOG_ERR, "ERROR ( %s/%s ): telemetry_daemon_msglog_file, telemetry_daemon_msglog_amqp_routing_key and telemetry_daemon_msglog_kafka_topic are mutually exclusive. Terminating.\n", config.name, t_data->log_str); exit_all(1); } } if (config.telemetry_dump_file || config.telemetry_dump_amqp_routing_key || config.telemetry_dump_kafka_topic) { if (config.telemetry_dump_file) telemetry_misc_db->dump_backend_methods++; if (config.telemetry_dump_amqp_routing_key) telemetry_misc_db->dump_backend_methods++; if (config.telemetry_dump_kafka_topic) telemetry_misc_db->dump_backend_methods++; if (telemetry_misc_db->dump_backend_methods > 1) { Log(LOG_ERR, "ERROR ( %s/%s ): telemetry_dump_file, telemetry_dump_amqp_routing_key and telemetry_dump_kafka_topic are mutually exclusive. Terminating.\n", config.name, t_data->log_str); exit_all(1); } } if (telemetry_misc_db->msglog_backend_methods) { telemetry_misc_db->peers_log = malloc(config.telemetry_max_peers*sizeof(telemetry_peer_log)); if (!telemetry_misc_db->peers_log) { Log(LOG_ERR, "ERROR ( %s/%s ): Unable to malloc() telemetry peers_log structure. Terminating.\n", config.name, t_data->log_str); exit_all(1); } memset(telemetry_misc_db->peers_log, 0, config.telemetry_max_peers*sizeof(telemetry_peer_log)); telemetry_peer_log_seq_init(&telemetry_misc_db->log_seq); if (config.telemetry_msglog_amqp_routing_key) { #ifdef WITH_RABBITMQ telemetry_daemon_msglog_init_amqp_host(); p_amqp_connect_to_publish(&telemetry_daemon_msglog_amqp_host); if (!config.telemetry_msglog_amqp_retry) config.telemetry_msglog_amqp_retry = AMQP_DEFAULT_RETRY; #else Log(LOG_WARNING, "WARN ( %s/%s ): p_amqp_connect_to_publish() not possible due to missing --enable-rabbitmq\n", config.name, t_data->log_str); #endif } if (config.telemetry_msglog_kafka_topic) { #ifdef WITH_KAFKA telemetry_daemon_msglog_init_kafka_host(); #else Log(LOG_WARNING, "WARN ( %s/%s ): p_kafka_connect_to_produce() not possible due to missing --enable-kafka\n", config.name, t_data->log_str); #endif } } if (config.telemetry_port_tcp) config.telemetry_sock = socket(((struct sockaddr *)&server)->sa_family, SOCK_STREAM, 0); else if (config.telemetry_port_udp) config.telemetry_sock = socket(((struct sockaddr *)&server)->sa_family, SOCK_DGRAM, 0); if (config.telemetry_sock < 0) { #if (defined ENABLE_IPV6) /* retry with IPv4 */ if (!config.telemetry_ip) { struct sockaddr_in *sa4 = (struct sockaddr_in *)&server; sa4->sin_family = AF_INET; sa4->sin_addr.s_addr = htonl(0); sa4->sin_port = htons(port); slen = sizeof(struct sockaddr_in); if (config.telemetry_port_tcp) config.telemetry_sock = socket(((struct sockaddr *)&server)->sa_family, SOCK_STREAM, 0); else if (config.telemetry_port_udp) config.telemetry_sock = socket(((struct sockaddr *)&server)->sa_family, SOCK_DGRAM, 0); } #endif if (config.telemetry_sock < 0) { Log(LOG_ERR, "ERROR ( %s/%s ): socket() failed. Terminating.\n", config.name, t_data->log_str); exit_all(1); } } if (config.telemetry_ipprec) { int opt = config.telemetry_ipprec << 5; rc = setsockopt(config.telemetry_sock, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)); if (rc < 0) Log(LOG_ERR, "WARN ( %s/%s ): setsockopt() failed for IP_TOS (errno: %d).\n", config.name, t_data->log_str, errno); } rc = setsockopt(config.telemetry_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)); if (rc < 0) Log(LOG_ERR, "WARN ( %s/%s ): setsockopt() failed for SO_REUSEADDR (errno: %d).\n", config.name, t_data->log_str, errno); #if (defined ENABLE_IPV6) && (defined IPV6_BINDV6ONLY) rc = setsockopt(config.telemetry_sock, IPPROTO_IPV6, IPV6_BINDV6ONLY, (char *) &no, (socklen_t) sizeof(no)); if (rc < 0) Log(LOG_ERR, "WARN ( %s/%s ): setsockopt() failed for IPV6_BINDV6ONLY (errno: %d).\n", config.name, t_data->log_str, errno); #endif if (config.telemetry_pipe_size) { int l = sizeof(config.telemetry_pipe_size); int saved = 0, obtained = 0; getsockopt(config.telemetry_sock, SOL_SOCKET, SO_RCVBUF, &saved, &l); Setsocksize(config.telemetry_sock, SOL_SOCKET, SO_RCVBUF, &config.telemetry_pipe_size, sizeof(config.telemetry_pipe_size)); getsockopt(config.telemetry_sock, SOL_SOCKET, SO_RCVBUF, &obtained, &l); Setsocksize(config.telemetry_sock, SOL_SOCKET, SO_RCVBUF, &saved, l); getsockopt(config.telemetry_sock, SOL_SOCKET, SO_RCVBUF, &obtained, &l); Log(LOG_INFO, "INFO ( %s/%s ): telemetry_daemon_pipe_size: obtained=%d target=%d.\n", config.name, t_data->log_str, obtained, config.telemetry_pipe_size); } rc = bind(config.telemetry_sock, (struct sockaddr *) &server, slen); if (rc < 0) { char null_ip_address[] = "0.0.0.0"; char *ip_address; ip_address = config.telemetry_ip ? config.telemetry_ip : null_ip_address; Log(LOG_ERR, "ERROR ( %s/%s ): bind() to ip=%s port=%u/%s failed (errno: %d).\n", config.name, t_data->log_str, ip_address, port, srv_proto, errno); exit_all(1); } if (config.telemetry_port_tcp) { rc = listen(config.telemetry_sock, 1); if (rc < 0) { Log(LOG_ERR, "ERROR ( %s/%s ): listen() failed (errno: %d).\n", config.name, t_data->log_str, errno); exit_all(1); } } /* Preparing for syncronous I/O multiplexing */ select_fd = 0; FD_ZERO(&bkp_read_descs); FD_SET(config.telemetry_sock, &bkp_read_descs); { char srv_string[INET6_ADDRSTRLEN]; struct host_addr srv_addr; u_int16_t srv_port; sa_to_addr(&server, &srv_addr, &srv_port); addr_to_str(srv_string, &srv_addr); Log(LOG_INFO, "INFO ( %s/%s ): waiting for telemetry data on %s:%u/%s\n", config.name, t_data->log_str, srv_string, srv_port, srv_proto); } /* Preparing ACL, if any */ if (config.telemetry_allow_file) load_allow_file(config.telemetry_allow_file, &allow); if (telemetry_misc_db->msglog_backend_methods) { #ifdef WITH_JANSSON if (!config.telemetry_msglog_output) config.telemetry_msglog_output = PRINT_OUTPUT_JSON; #else Log(LOG_WARNING, "WARN ( %s/%s ): telemetry_daemon_msglog_output set to json but will produce no output (missing --enable-jansson).\n", config.name, t_data->log_str); #endif } if (telemetry_misc_db->dump_backend_methods) { #ifdef WITH_JANSSON if (!config.telemetry_dump_output) config.telemetry_dump_output = PRINT_OUTPUT_JSON; #else Log(LOG_WARNING, "WARN ( %s/%s ): telemetry_table_dump_output set to json but will produce no output (missing --enable-jansson).\n", config.name, t_data->log_str); #endif } if (telemetry_misc_db->dump_backend_methods) { char dump_roundoff[] = "m"; time_t tmp_time; if (config.telemetry_dump_refresh_time) { gettimeofday(&telemetry_misc_db->log_tstamp, NULL); dump_refresh_deadline = telemetry_misc_db->log_tstamp.tv_sec; tmp_time = roundoff_time(dump_refresh_deadline, dump_roundoff); while ((tmp_time+config.telemetry_dump_refresh_time) < dump_refresh_deadline) { tmp_time += config.telemetry_dump_refresh_time; } dump_refresh_deadline = tmp_time; dump_refresh_deadline += config.telemetry_dump_refresh_time; /* it's a deadline not a basetime */ } else { config.telemetry_dump_file = NULL; telemetry_misc_db->dump_backend_methods = FALSE; Log(LOG_WARNING, "WARN ( %s/%s ): Invalid 'telemetry_dump_refresh_time'.\n", config.name, t_data->log_str); } if (config.telemetry_dump_amqp_routing_key) telemetry_dump_init_amqp_host(); if (config.telemetry_dump_kafka_topic) telemetry_dump_init_kafka_host(); } select_fd = bkp_select_fd = (config.telemetry_sock + 1); recalc_fds = FALSE; telemetry_link_misc_structs(telemetry_misc_db); for (;;) { select_again: if (recalc_fds) { select_fd = config.telemetry_sock; max_peers_idx = -1; /* .. since valid indexes include 0 */ for (peers_idx = 0, peers_num = 0; peers_idx < config.telemetry_max_peers; peers_idx++) { if (select_fd < telemetry_peers[peers_idx].fd) select_fd = telemetry_peers[peers_idx].fd; if (telemetry_peers[peers_idx].fd) { max_peers_idx = peers_idx; peers_num++; } } select_fd++; max_peers_idx++; bkp_select_fd = select_fd; recalc_fds = FALSE; } else select_fd = bkp_select_fd; memcpy(&read_descs, &bkp_read_descs, sizeof(bkp_read_descs)); if (telemetry_misc_db->dump_backend_methods) { int delta; calc_refresh_timeout_sec(dump_refresh_deadline, telemetry_misc_db->log_tstamp.tv_sec, &delta); dump_refresh_timeout.tv_sec = delta; dump_refresh_timeout.tv_usec = 0; drt_ptr = &dump_refresh_timeout; } else drt_ptr = NULL; select_num = select(select_fd, &read_descs, NULL, NULL, drt_ptr); if (select_num < 0) goto select_again; // XXX: UDP case: timeout handling (to be tested) if (config.telemetry_port_udp) { now = time(NULL); if (now > (last_udp_timeout_check + TELEMETRY_UDP_TIMEOUT_INTERVAL)) { for (peers_idx = 0; peers_idx < config.telemetry_max_peers; peers_idx++) { telemetry_peer_udp_timeout *peer_udp_timeout; peer = &telemetry_peers[peers_idx]; peer_z = &telemetry_peers_z[peers_idx]; peer_udp_timeout = &telemetry_peers_udp_timeout[peers_idx]; if (peer->fd) { if (now > (peer_udp_timeout->last_msg + config.telemetry_udp_timeout)) { Log(LOG_INFO, "INFO ( %s/%s ): [%s] telemetry UDP peer removed (timeout).\n", config.name, t_data->log_str, peer->addr_str); telemetry_peer_close(peer, FUNC_TYPE_TELEMETRY); if (telemetry_is_zjson(decoder)) telemetry_peer_z_close(peer_z); recalc_fds = TRUE; } } } } } if (reload_log_telemetry_thread) { for (peers_idx = 0; peers_idx < config.telemetry_max_peers; peers_idx++) { if (telemetry_misc_db->peers_log[peers_idx].fd) { fclose(telemetry_misc_db->peers_log[peers_idx].fd); telemetry_misc_db->peers_log[peers_idx].fd = open_output_file(telemetry_misc_db->peers_log[peers_idx].filename, "a", FALSE); setlinebuf(telemetry_misc_db->peers_log[peers_idx].fd); } else break; } } if (telemetry_misc_db->msglog_backend_methods || telemetry_misc_db->dump_backend_methods) { gettimeofday(&telemetry_misc_db->log_tstamp, NULL); compose_timestamp(telemetry_misc_db->log_tstamp_str, SRVBUFLEN, &telemetry_misc_db->log_tstamp, TRUE, config.timestamps_since_epoch); if (telemetry_misc_db->dump_backend_methods) { while (telemetry_misc_db->log_tstamp.tv_sec > dump_refresh_deadline) { telemetry_handle_dump_event(t_data); dump_refresh_deadline += config.telemetry_dump_refresh_time; } } #ifdef WITH_RABBITMQ if (config.telemetry_msglog_amqp_routing_key) { time_t last_fail = P_broker_timers_get_last_fail(&telemetry_daemon_msglog_amqp_host.btimers); if (last_fail && ((last_fail + P_broker_timers_get_retry_interval(&telemetry_daemon_msglog_amqp_host.btimers)) <= telemetry_misc_db->log_tstamp.tv_sec)) { telemetry_daemon_msglog_init_amqp_host(); p_amqp_connect_to_publish(&telemetry_daemon_msglog_amqp_host); } } #endif #ifdef WITH_KAFKA if (config.telemetry_msglog_kafka_topic) { time_t last_fail = P_broker_timers_get_last_fail(&telemetry_daemon_msglog_kafka_host.btimers); if (last_fail && ((last_fail + P_broker_timers_get_retry_interval(&telemetry_daemon_msglog_kafka_host.btimers)) <= telemetry_misc_db->log_tstamp.tv_sec)) telemetry_daemon_msglog_init_kafka_host(); } #endif } /* If select_num == 0 then we got out of select() due to a timeout rather than because we had a message from a peeer to handle. By now we did all routine checks and can happily return to selet() again. */ if (!select_num) goto select_again; /* New connection is coming in */ if (FD_ISSET(config.telemetry_sock, &read_descs)) { if (config.telemetry_port_tcp) { fd = accept(config.telemetry_sock, (struct sockaddr *) &client, &clen); if (fd == ERR) goto read_data; } else if (config.telemetry_port_udp) { char dummy_local_buf[TRUE]; ret = recvfrom(config.telemetry_sock, dummy_local_buf, TRUE, MSG_PEEK, (struct sockaddr *) &client, &clen); if (ret <= 0) goto select_again; else fd = config.telemetry_sock; } #if defined ENABLE_IPV6 ipv4_mapped_to_ipv4(&client); #endif /* If an ACL is defined, here we check against and enforce it */ if (allow.num) allowed = check_allow(&allow, (struct sockaddr *)&client); else allowed = TRUE; if (!allowed) { if (config.telemetry_port_tcp) close(fd); goto read_data; } /* XXX: UDP case may be optimized further */ if (config.telemetry_port_udp) { telemetry_peer_udp_cache *tpuc_ret; u_int16_t client_port; sa_to_addr(&client, &tpuc.addr, &client_port); tpuc_ret = pm_tfind(&tpuc, &telemetry_peers_udp_cache, telemetry_tpuc_addr_cmp); if (tpuc_ret) { peer = &telemetry_peers[tpuc_ret->index]; telemetry_peers_udp_timeout[tpuc_ret->index].last_msg = now; goto read_data; } } for (peer = NULL, peers_idx = 0; peers_idx < config.telemetry_max_peers; peers_idx++) { if (!telemetry_peers[peers_idx].fd) { peer = &telemetry_peers[peers_idx]; if (telemetry_peer_init(peer, FUNC_TYPE_TELEMETRY)) peer = NULL; if (telemetry_is_zjson(decoder)) { peer_z = &telemetry_peers_z[peers_idx]; if (telemetry_peer_z_init(peer_z)) { peer = NULL; peer_z = NULL; } } if (peer) { recalc_fds = TRUE; if (config.telemetry_port_udp) { tpuc.index = peers_idx; telemetry_peers_udp_timeout[peers_idx].last_msg = now; if (!pm_tsearch(&tpuc, &telemetry_peers_udp_cache, telemetry_tpuc_addr_cmp, sizeof(telemetry_peer_udp_cache))) Log(LOG_WARNING, "WARN ( %s/%s ): tsearch() unable to insert in UDP peers cache.\n", config.name, t_data->log_str); } } break; } } if (!peer) { /* We briefly accept the new connection to be able to drop it */ Log(LOG_ERR, "ERROR ( %s/%s ): Insufficient number of telemetry peers has been configured by telemetry_max_peers (%d).\n", config.name, t_data->log_str, config.telemetry_max_peers); if (config.telemetry_port_tcp) close(fd); goto read_data; } peer->fd = fd; if (config.telemetry_port_tcp) FD_SET(peer->fd, &bkp_read_descs); peer->addr.family = ((struct sockaddr *)&client)->sa_family; if (peer->addr.family == AF_INET) { peer->addr.address.ipv4.s_addr = ((struct sockaddr_in *)&client)->sin_addr.s_addr; peer->tcp_port = ntohs(((struct sockaddr_in *)&client)->sin_port); } #if defined ENABLE_IPV6 else if (peer->addr.family == AF_INET6) { memcpy(&peer->addr.address.ipv6, &((struct sockaddr_in6 *)&client)->sin6_addr, 16); peer->tcp_port = ntohs(((struct sockaddr_in6 *)&client)->sin6_port); } #endif addr_to_str(peer->addr_str, &peer->addr); if (telemetry_misc_db->msglog_backend_methods) telemetry_peer_log_init(peer, config.telemetry_msglog_output, FUNC_TYPE_TELEMETRY); if (telemetry_misc_db->dump_backend_methods) telemetry_dump_init_peer(peer); peers_num++; Log(LOG_INFO, "INFO ( %s/%s ): [%s] telemetry peers usage: %u/%u\n", config.name, t_data->log_str, peer->addr_str, peers_num, config.telemetry_max_peers); } read_data: /* We have something coming in: let's lookup which peer is that. FvD: To avoid starvation of the "later established" peers, we offset the start of the search in a round-robin style. */ if (config.telemetry_port_tcp) { for (peer = NULL, peers_idx = 0; peers_idx < max_peers_idx; peers_idx++) { int loc_idx = (peers_idx + peers_idx_rr) % max_peers_idx; if (telemetry_peers[loc_idx].fd && FD_ISSET(telemetry_peers[loc_idx].fd, &read_descs)) { peer = &telemetry_peers[loc_idx]; if (telemetry_is_zjson(decoder)) peer_z = &telemetry_peers_z[loc_idx]; peers_idx_rr = (peers_idx_rr + 1) % max_peers_idx; break; } } } if (!peer) goto select_again; recv_flags = 0; switch (decoder) { case TELEMETRY_DECODER_JSON: ret = telemetry_recv_json(peer, 0, &recv_flags); data_decoder = TELEMETRY_DATA_DECODER_JSON; break; case TELEMETRY_DECODER_ZJSON: ret = telemetry_recv_zjson(peer, peer_z, 0, &recv_flags); data_decoder = TELEMETRY_DATA_DECODER_JSON; break; case TELEMETRY_DECODER_CISCO: ret = telemetry_recv_cisco(peer, &recv_flags, &data_decoder); break; case TELEMETRY_DECODER_CISCO_JSON: ret = telemetry_recv_cisco_json(peer, &recv_flags); data_decoder = TELEMETRY_DATA_DECODER_JSON; break; case TELEMETRY_DECODER_CISCO_ZJSON: ret = telemetry_recv_cisco_zjson(peer, peer_z, &recv_flags); data_decoder = TELEMETRY_DATA_DECODER_JSON; break; case TELEMETRY_DECODER_CISCO_GPB: ret = telemetry_recv_cisco_gpb(peer, &recv_flags); data_decoder = TELEMETRY_DATA_DECODER_GPB; break; case TELEMETRY_DECODER_CISCO_GPB_KV: ret = telemetry_recv_cisco_gpb_kv(peer, &recv_flags); data_decoder = TELEMETRY_DATA_DECODER_GPB; break; default: ret = TRUE; recv_flags = ERR; data_decoder = TELEMETRY_DATA_DECODER_UNKNOWN; break; } if (ret <= 0) { Log(LOG_INFO, "INFO ( %s/%s ): [%s] connection reset by peer (%d).\n", config.name, t_data->log_str, peer->addr_str, errno); FD_CLR(peer->fd, &bkp_read_descs); telemetry_peer_close(peer, FUNC_TYPE_TELEMETRY); if (telemetry_is_zjson(decoder)) telemetry_peer_z_close(peer_z); recalc_fds = TRUE; } else { if (recv_flags != ERR) telemetry_process_data(peer, t_data, data_decoder); } } }
int parse_settings( int argc, char *argv[], struct settings *settings ) { int c; const char *optstring = "DhvVtTReunqs:d:p:c:i:H:r:m:"; assert ( settings != NULL ); // Default arguments settings->daemon = 0; settings->message_size = 1024; settings->socket_size = ~0; settings->rate = ~0; settings->disable_nagles = 0; settings->duration = 10; settings->server_host = NULL; settings->port = 1234; settings->verbose = 0; settings->dirty = 0; settings->timestamp = 0; settings->confidence_lvl = 0.0; settings->confidence_int = 0.0; settings->min_iterations = 1; settings->max_iterations = 1; settings->threaded_model = MODEL_THREADED; settings->reverse = 0; settings->quiet = 0; settings->type = SOCK_STREAM; settings->protocol = IPPROTO_TCP; settings->test = NULL; settings->tests = 0; if ( argc == 1 ) { print_usage(); return -1; } // A first pass of getopt to work out if we are a daemon while ((c = getopt(argc, argv, optstring)) != -1) { switch ( c ) { // daemon mode (wait for incoming tests) case 'D': settings->daemon = 1; break; case 'h': print_usage(); return -1; // Increase the verbose level case 'v': settings->verbose = 1; break; case 'V': print_version(); return -1; case ':': fprintf(stderr, "Missing argument for (%s)\n", argv[optind-1] ); return -1; case '?': fprintf(stderr, "Unknown argument (%s)\n", argv[optind-1] ); return -1; default: break; } } if ( settings->daemon && optind < argc ) { fprintf(stderr, "Tests can not be specified on the command line in daemon mode\n" ); return -1; } // Reset the parsing to the beginning optind = 1; #ifdef __FreeBSD__ optreset = 1; #endif // Second pass which actually does the work while ((c = getopt(argc, argv, optstring)) != -1) { switch ( c ) { case 'c': { double level = 95.0, interval = 5.0; if ( settings->daemon ) { fprintf(stdout, "Unable to set confidence interval when in daemon mode\n"); return -1; } if ( sscanf( optarg, "%lf,%lf", &level, &interval ) < 2 ) { fprintf(stdout, "%lf%% Confidence interval defaulted to %lf percent\n", level, interval); } if (level != 75.0 && level != 90.0 && level != 95.0 && level != 97.5 && level != 99.0 && level != 99.5 && level != 99.95) { fprintf(stderr, "Confidence Level must be {75, 90, 95, 97.5, 99, 99.5, 99.95}. Given (%s)\n", optarg); return -1; } settings->confidence_lvl = level; settings->confidence_int = interval; break; } // Duration case 'd': if ( settings->daemon ) { fprintf(stdout, "Unable to set duration when in daemon mode\n"); return -1; } settings->duration = atoi( optarg ); if ( settings->duration == 0 ) { fprintf(stderr, "Invalid duration given (%s)\n", optarg ); return -1; } break; case 'i': { // min,max interations unsigned int min = 0, max = 0; if ( settings->daemon ) { fprintf(stdout, "Unable to set iterations when in daemon mode\n"); return -1; } if ( sscanf( optarg, "%u,%u", &min, &max ) < 2 ) { if (sscanf( optarg, "%u", &max ) == 1) min = max; // Let the user specify just one value } if ( min > max || max == 0 ) { fprintf(stderr, "Invalid min/max iterations(%s)\n", optarg ); return -1; } settings->min_iterations = min; settings->max_iterations = max; break; } case 'H': { // remote host struct sockaddr_storage addr; socklen_t addr_len = sizeof(addr); if ( settings->daemon ) { fprintf(stdout, "Unable to set remote host when in daemon mode\n"); return -1; } if ( str_to_addr( optarg, (struct sockaddr *)&addr, &addr_len ) ) { fprintf(stderr, "Invalid host name (%s)\n", optarg ); return -1; } settings->server_host = optarg; break; } // Disable nagles algorithm (ie NO delay) case 'n': if ( settings->daemon ) { fprintf(stdout, "Unable to disable Nagles when in daemon mode\n"); return -1; } settings->disable_nagles = 1; break; case 'm' : if ( settings->daemon ) { fprintf(stdout, "Unable to set threading model when in daemon mode\n"); return -1; } if(strcmp(optarg, "p")==0) settings->threaded_model = MODEL_PROCESS; else if( strcmp(optarg, "t")==0) settings->threaded_model = MODEL_THREADED; else { fprintf(stderr, "Invalid threading model set to (%s)\n", optarg ); return -1; } break; case 'q': if ( settings->daemon ) { fprintf(stdout, "Unable to set quiet when in daemon mode\n"); return -1; } settings->quiet = 1; break; // Parse the message size case 's': if ( settings->daemon ) { fprintf(stdout, "Unable to set message size when in daemon mode\n"); return -1; } settings->message_size = atoi( optarg ); if ( settings->message_size == 0 ) { fprintf(stderr, "Invalid message size given (%s)\n", optarg ); return -1; } break; // Send rate case 'r': if ( settings->daemon ) { fprintf(stdout, "Unable to set send rate when in daemon mode\n"); return -1; } settings->rate = atoi( optarg ); if ( settings->rate == 0 ) { fprintf(stderr, "Invalid send rate given (%s)\n", optarg ); return -1; } break; // Parse the port case 'p': if ( settings->daemon ) { fprintf(stdout, "Unable to set port when in daemon mode\n"); return -1; } settings->port = atoi( optarg ); if ( settings->port == 0 ) { fprintf(stderr, "Invalid port number given (%s)\n", optarg ); return -1; } break; // Dirty the data case 'e': if ( settings->daemon ) { fprintf(stdout, "Unable to eat the data when in daemon mode\n"); return -1; } settings->dirty = 1; break; // Reverse mode case 'R': if ( settings->daemon ) { fprintf(stdout, "Unable to set reverse mode when in daemon mode\n"); return -1; } settings->reverse = 1; break; case 'T': #ifdef WIN32 fprintf(stdout, "Timestamps option unavailable on windows\n"); return -1; #endif if ( settings->daemon ) { fprintf(stdout, "Unable to set timestamps when in daemon mode\n"); return -1; } settings->timestamp = 1; break; // TCP/UDP case 't': if ( settings->daemon ) { fprintf(stdout, "Unable to set TCP when in daemon mode\n"); return -1; } settings->type = SOCK_STREAM; settings->protocol = IPPROTO_TCP; break; case 'u': if ( settings->daemon ) { fprintf(stdout, "Unable to set UDP when in daemon mode\n"); return -1; } settings->type = SOCK_DGRAM; settings->protocol = IPPROTO_UDP; break; // Ignore the following parameters as they have been parsed in a previous getopt loop case 'D': case 'h': case 'v': case 'V': break; default: fprintf(stderr, "Argument not implemented (yet) (%c)\n", c ); return -1; } } if ( settings->disable_nagles && settings->protocol != IPPROTO_TCP ) { fprintf(stderr, "Must use TCP when disabling Nagles\n" ); return -1; } // if( settings->timestamp && settings->message_size < sizeof(unsigned long long) ) { // fprintf(stderr, "Message size must be greater than %u when using timestamps\n", (unsigned int) sizeof(unsigned long long) ); // return -1; // } // Try and parse anything else left on the end // 1{0-0} 10{1-1} 3{0-1}, 1 connection core 0 to core 0, 10 connections core 1 to core 1, and 3 connections core 0 to core 1 while (optind < argc) { struct test * test; assert( !settings->daemon ); // Malloc space for this extra test settings->test = realloc ( settings->test, sizeof(*settings->test) * (settings->tests + 1) ); test = &settings->test [ settings->tests ]; // Parse N{C-S} if ( parse_test ( settings, argv[optind], test ) != 0 ) { fprintf(stderr, "Unknown argument (%s)\n", argv[optind] ); return -1; } // Check all the paramters make sense if ( test->clientcores == 0 || test->servercores == 0 ) { fprintf(stderr, "Cores of zero will not run on any core (%s)\n", argv[optind] ); return -1; } // TODO check if the server is remote, and then decide if the cores make sense if ( test->clientcores >= (unsigned int)(1 << max_cores) || test->servercores >= (unsigned int)(1 << max_cores) ) { fprintf(stderr, "Cores must not be greater than %d (%s)\n", max_cores, argv[optind] ); return -1; } settings->tests++; optind++; } // If there are no tests then error if ( settings->tests == 0 && !settings->daemon ) { fprintf(stderr, "No tests were specified\n"); return -1; } settings->clientcores = count_client_cores ( settings->test, settings->tests ); settings->servercores = count_server_cores ( settings->test, settings->tests ); return 0; }
/* * Funzione prova a connetersi ai superpeer indicati nella lista passata come parametro. * Ritorna 0 in caso di successo e -1 se si è verificato un errore o se non è riuscita * a connettersi a nessun superpeer della lista. */ int join_overlay(const struct sockaddr_in *sp_addr_list, int list_len) { int i, ok = 1; int sock_tmp; int addr_check = 0; int j, nread; struct sockaddr_in *addr_list; struct packet recv_pck; if (list_len > max_tcp_sock / 2) { near_str = (char *)realloc(near_str, list_len * 2 * ADDR_STR_LEN); memset(near_str + max_tcp_sock * ADDR_STR_LEN, 0, (list_len * 2 - max_tcp_sock) * ADDR_STR_LEN); max_tcp_sock = list_len * 2; } for (i = 0; i < list_len; i ++) { if (get_near_by_addr(&sp_addr_list[i]) != NULL) { continue; } if (ok) { if ((sock_tmp = tcp_socket()) < 0) { perror("join_overlay error - can't initialize tcp socket"); return -1; } //printf("SOCKET: %d\n", sock_tmp); // printf("LISTLEN: %d\n", list_len); } printf("join_overlay - addr: %s:%d\n", inet_ntoa(sp_addr_list[i].sin_addr), ntohs(sp_addr_list[i].sin_port)); if (tcp_connect(sock_tmp, &sp_addr_list[i]) < 0) { perror("join_overlay error - can't connect to superpeer"); ok = 0; continue; //provo il prossimo indirizzo } else { printf("Connected with superpeer %s:%d\n", inet_ntoa(sp_addr_list[i].sin_addr), ntohs(sp_addr_list[i].sin_port)); if (addr_check == 0) { get_local_addr(sock_tmp, &myaddr); addr_check = 1; } ok = 1; if ((nread = recv_packet_tcp(sock_tmp, &recv_pck)) < 0) { perror("join_overlay error - recv_packet_tcp failed\n"); return -1; } else if (nread == 0) { printf("join_overlay - connection closed by superpeer\n"); if (close(sock_tmp) < 0) { perror("join_overlay error - close failed"); return -1; } continue; } if (!strncmp(recv_pck.cmd, CMD_ACK, CMD_STR_LEN)) { if (write(sock_tmp, (char *)&conf.udp_port, sizeof(conf.udp_port)) < 0) { perror("join_overlay error - write failed\n"); return -1; } fd_add(sock_tmp); if (insert_near(sock_tmp, &sp_addr_list[i]) < 0) { fprintf(stderr, "join_overlay error - insert_near failed\n"); return -1; } addr2str(near_str + nsock * 6, sp_addr_list[i].sin_addr.s_addr, sp_addr_list[i].sin_port); addr_list = str_to_addr(near_str, max_tcp_sock); for(j = 0; j < max_tcp_sock; j ++){ printf("join_overlay - near %s:%d\n", inet_ntoa(addr_list[j].sin_addr), ntohs(addr_list[j].sin_port)); } nsock ++; } else if (!strncmp(recv_pck.cmd, CMD_ERR, CMD_STR_LEN)) { printf("RICEVUTO ERR\n"); printf("join_overlay - connection closed by superpeer\n"); if (close(sock_tmp) < 0) { perror("join_overlay error - close failed"); return -1; } continue; } else { fprintf(stderr, "join_overlay error - packet not expected\n"); if (close(sock_tmp) < 0) { perror("join_overlay error - close failed"); return -1; } continue; } } } if (!ok) { close(sock_tmp); } if (nsock != list_len) { printf("join_overlay error - can't connect to all superpeer in the list\n"); return 1; } return 0; }
int main(int argc, char **argv) { int ch, longindex, ret, port = SD_LISTEN_PORT, io_port = SD_LISTEN_PORT; int rc = 1; const char *dirp = DEFAULT_OBJECT_DIR, *short_options; char *dir, *p, *pid_file = NULL, *bindaddr = NULL, log_path[PATH_MAX], *argp = NULL; bool explicit_addr = false; bool daemonize = true; int32_t nr_vnodes = -1; int64_t zone = -1; struct cluster_driver *cdrv; struct option *long_options; const char *http_options = NULL; static struct logger_user_info sheep_info; struct stat logdir_st; enum log_dst_type log_dst_type; sys->cinfo.flags |= SD_CLUSTER_FLAG_AUTO_VNODES; sys->node_status = SD_NODE_STATUS_INITIALIZATION; sys->rthrottling.max_exec_count = 0; sys->rthrottling.queue_work_interval = 0; sys->rthrottling.throttling = false; install_crash_handler(crash_handler); signal(SIGPIPE, SIG_IGN); install_sighandler(SIGHUP, sighup_handler, false); long_options = build_long_options(sheep_options); short_options = build_short_options(sheep_options); while ((ch = getopt_long(argc, argv, short_options, long_options, &longindex)) >= 0) { switch (ch) { case 'p': port = strtol(optarg, &p, 10); if (optarg == p || port < 1 || UINT16_MAX < port || *p != '\0') { sd_err("Invalid port number '%s'", optarg); exit(1); } break; case 'P': pid_file = optarg; break; case 'r': http_options = optarg; break; case 'l': if (option_parse(optarg, ",", log_parsers) < 0) exit(1); break; case 'n': sys->nosync = true; break; case 'y': if (!str_to_addr(optarg, sys->this_node.nid.addr)) { sd_err("Invalid address: '%s'", optarg); exit(1); } explicit_addr = true; break; case 'D': sys->backend_dio = true; break; case 'f': daemonize = false; break; case 'g': if (nr_vnodes > 0) { sd_err("Options '-g' and '-V' can not be both specified"); exit(1); } nr_vnodes = 0; break; case 'z': zone = strtol(optarg, &p, 10); if (optarg == p || zone < 0 || UINT32_MAX < zone || *p != '\0') { sd_err("Invalid zone id '%s': must be " "an integer between 0 and %u", optarg, UINT32_MAX); exit(1); } sys->this_node.zone = zone; break; case 'u': sys->upgrade = true; break; case 'c': sys->cdrv = find_cdrv(optarg); if (!sys->cdrv) { sd_err("Invalid cluster driver '%s'", optarg); fprintf(stderr, "Supported drivers:"); FOR_EACH_CLUSTER_DRIVER(cdrv) { fprintf(stderr, " %s", cdrv->name); } fprintf(stderr, "\n"); exit(1); } sys->cdrv_option = get_cdrv_option(sys->cdrv, optarg); break; case 'w': sys->enable_object_cache = true; sys->object_cache_size = 0; if (option_parse(optarg, ",", cache_parsers) < 0) exit(1); if (sys->object_cache_size == 0) { sd_err("object cache size is not set"); exit(1); } break; case 'i': if (option_parse(optarg, ",", ionic_parsers) < 0) exit(1); if (!str_to_addr(io_addr, sys->this_node.nid.io_addr)) { sd_err("Bad addr: '%s'", io_addr); exit(1); } if (io_pt) if (sscanf(io_pt, "%u", &io_port) != 1) { sd_err("Bad port '%s'", io_pt); exit(1); } sys->this_node.nid.io_port = io_port; break; case 'j': uatomic_set_true(&sys->use_journal); if (option_parse(optarg, ",", journal_parsers) < 0) exit(1); if (!jsize) { sd_err("you must specify size for journal"); exit(1); } break; case 'b': if (!inetaddr_is_valid(optarg)) exit(1); bindaddr = optarg; break; case 'h': usage(0); break; case 'R': if (option_parse(optarg, ",", recovery_parsers) < 0) exit(1); sys->rthrottling.max_exec_count = max_exec_count; sys->rthrottling.queue_work_interval = queue_work_interval; if (max_exec_count > 0 && queue_work_interval > 0) sys->rthrottling.throttling = true; break; case 'v': fprintf(stdout, "Sheepdog daemon version %s\n", PACKAGE_VERSION); exit(0); break; case 'V': sys->cinfo.flags &= ~SD_CLUSTER_FLAG_AUTO_VNODES; if (nr_vnodes == 0) { sd_err("Options '-g' and '-V' can not be both specified"); exit(1); } nr_vnodes = strtol(optarg, &p, 10); if (optarg == p || nr_vnodes < 1 || UINT16_MAX < nr_vnodes || *p != '\0') { sd_err("Invalid number of vnodes '%s': must be " "an integer between 1 and %u", optarg, UINT16_MAX); exit(1); } break; case 'W': wildcard_recovery = true; break; default: usage(1); break; } }
void skinny_bmp_daemon() { int slen, clen, ret, rc, peers_idx, allowed, yes=1; char bmp_packet[BMP_MAX_PACKET_SIZE], *bmp_packet_ptr; time_t now; afi_t afi; safi_t safi; struct bgp_peer *peer; #if defined ENABLE_IPV6 struct sockaddr_storage server, client; struct ipv6_mreq multi_req6; #else struct sockaddr server, client; #endif struct hosts_table allow; struct host_addr addr; /* BMP peer batching vars */ int bmp_current_batch_elem = 0; time_t bmp_current_batch_stamp_base = 0; /* select() stuff */ fd_set read_descs, bkp_read_descs; int select_fd, select_num; /* logdump time management */ time_t dump_refresh_deadline; struct timeval dump_refresh_timeout, *drt_ptr; /* initial cleanups */ reload_log_bmp_thread = FALSE; memset(&server, 0, sizeof(server)); memset(&client, 0, sizeof(client)); memset(bmp_packet, 0, BMP_MAX_PACKET_SIZE); memset(&allow, 0, sizeof(struct hosts_table)); clen = sizeof(client); /* socket creation for BMP server: IPv4 only */ #if (defined ENABLE_IPV6) if (!config.nfacctd_bmp_ip) { struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&server; sa6->sin6_family = AF_INET6; sa6->sin6_port = htons(config.nfacctd_bmp_port); slen = sizeof(struct sockaddr_in6); } #else if (!config.nfacctd_bmp_ip) { struct sockaddr_in *sa4 = (struct sockaddr_in *)&server; sa4->sin_family = AF_INET; sa4->sin_addr.s_addr = htonl(0); sa4->sin_port = htons(config.nfacctd_bmp_port); slen = sizeof(struct sockaddr_in); } #endif else { trim_spaces(config.nfacctd_bmp_ip); ret = str_to_addr(config.nfacctd_bmp_ip, &addr); if (!ret) { Log(LOG_ERR, "ERROR ( %s/core/BMP ): 'bmp_daemon_ip' value is not a valid IPv4/IPv6 address. Terminating thread.\n", config.name); exit_all(1); } slen = addr_to_sa((struct sockaddr *)&server, &addr, config.nfacctd_bmp_port); } if (!config.nfacctd_bmp_max_peers) config.nfacctd_bmp_max_peers = BMP_MAX_PEERS_DEFAULT; Log(LOG_INFO, "INFO ( %s/core/BMP ): maximum BMP peers allowed: %d\n", config.name, config.nfacctd_bmp_max_peers); bmp_peers = malloc(config.nfacctd_bmp_max_peers*sizeof(struct bgp_peer)); if (!bmp_peers) { Log(LOG_ERR, "ERROR ( %s/core/BMP ): Unable to malloc() BMP peers structure. Terminating thread.\n", config.name); exit_all(1); } memset(bmp_peers, 0, config.nfacctd_bmp_max_peers*sizeof(struct bgp_peer)); if (config.nfacctd_bmp_msglog_file && config.nfacctd_bmp_msglog_amqp_routing_key) { Log(LOG_ERR, "ERROR ( %s/core/BMP ): bmp_daemon_msglog_file and bmp_daemon_msglog_amqp_routing_key are mutually exclusive. Terminating thread.\n", config.name); exit_all(1); } if (config.bmp_dump_file && config.bmp_dump_amqp_routing_key) { Log(LOG_ERR, "ERROR ( %s/core/BMP ): bmp_dump_file and bmp_dump_amqp_routing_key are mutually exclusive. Terminating thread.\n", config.name); exit_all(1); } if (config.nfacctd_bmp_msglog_file || config.nfacctd_bmp_msglog_amqp_routing_key) { bmp_peers_log = malloc(config.nfacctd_bmp_max_peers*sizeof(struct bgp_peer_log)); if (!bmp_peers_log) { Log(LOG_ERR, "ERROR ( %s/core/BMP ): Unable to malloc() BMP peers log structure. Terminating thread.\n", config.name); exit_all(1); } memset(bmp_peers_log, 0, config.nfacctd_bmp_max_peers*sizeof(struct bgp_peer_log)); bgp_peer_log_seq_init(&bmp_log_seq); if (config.nfacctd_bmp_msglog_amqp_routing_key) { #ifdef WITH_RABBITMQ bmp_daemon_msglog_init_amqp_host(); p_amqp_connect_to_publish(&bmp_daemon_msglog_amqp_host); if (!config.nfacctd_bmp_msglog_amqp_retry) config.nfacctd_bmp_msglog_amqp_retry = AMQP_DEFAULT_RETRY; #else Log(LOG_WARNING, "WARN ( %s/core/BMP ): p_amqp_connect_to_publish() not possible due to missing --enable-rabbitmq\n", config.name); #endif } } if (!config.bmp_table_attr_hash_buckets) config.bmp_table_attr_hash_buckets = HASHTABSIZE; bmp_attr_init(); if (!config.bmp_table_peer_buckets) config.bmp_table_peer_buckets = DEFAULT_BGP_INFO_HASH; if (!config.bmp_table_per_peer_buckets) config.bmp_table_per_peer_buckets = DEFAULT_BGP_INFO_PER_PEER_HASH; if (config.bmp_table_per_peer_hash == BGP_ASPATH_HASH_PATHID) bmp_route_info_modulo = bgp_route_info_modulo_pathid; else { Log(LOG_ERR, "ERROR ( %s/core/BMP ): Unknown 'bmp_table_per_peer_hash' value. Terminating thread.\n", config.name); exit_all(1); } config.bmp_sock = socket(((struct sockaddr *)&server)->sa_family, SOCK_STREAM, 0); if (config.bmp_sock < 0) { #if (defined ENABLE_IPV6) /* retry with IPv4 */ if (!config.nfacctd_bmp_ip) { struct sockaddr_in *sa4 = (struct sockaddr_in *)&server; sa4->sin_family = AF_INET; sa4->sin_addr.s_addr = htonl(0); sa4->sin_port = htons(config.nfacctd_bmp_port); slen = sizeof(struct sockaddr_in); config.bmp_sock = socket(((struct sockaddr *)&server)->sa_family, SOCK_STREAM, 0); } #endif if (config.bmp_sock < 0) { Log(LOG_ERR, "ERROR ( %s/core/BMP ): thread socket() failed. Terminating thread.\n", config.name); exit_all(1); } } if (config.nfacctd_bmp_ipprec) { int opt = config.nfacctd_bmp_ipprec << 5; rc = setsockopt(config.bmp_sock, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)); if (rc < 0) Log(LOG_ERR, "WARN ( %s/core/BMP ): setsockopt() failed for IP_TOS (errno: %d).\n", config.name, errno); } rc = setsockopt(config.bmp_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)); if (rc < 0) Log(LOG_ERR, "WARN ( %s/core/BMP ): setsockopt() failed for SO_REUSEADDR (errno: %d).\n", config.name, errno); if (config.nfacctd_bmp_pipe_size) { int l = sizeof(config.nfacctd_bmp_pipe_size); int saved = 0, obtained = 0; getsockopt(config.bmp_sock, SOL_SOCKET, SO_RCVBUF, &saved, &l); Setsocksize(config.bmp_sock, SOL_SOCKET, SO_RCVBUF, &config.nfacctd_bmp_pipe_size, sizeof(config.nfacctd_bmp_pipe_size)); getsockopt(config.bmp_sock, SOL_SOCKET, SO_RCVBUF, &obtained, &l); Setsocksize(config.bmp_sock, SOL_SOCKET, SO_RCVBUF, &saved, l); getsockopt(config.bmp_sock, SOL_SOCKET, SO_RCVBUF, &obtained, &l); Log(LOG_INFO, "INFO ( %s/core/BMP ): bmp_daemon_pipe_size: obtained=%d target=%d.\n", config.name, obtained, config.nfacctd_bmp_pipe_size); } rc = bind(config.bmp_sock, (struct sockaddr *) &server, slen); if (rc < 0) { char null_ip_address[] = "0.0.0.0"; char *ip_address; ip_address = config.nfacctd_bmp_ip ? config.nfacctd_bmp_ip : null_ip_address; Log(LOG_ERR, "ERROR ( %s/core/BMP ): bind() to ip=%s port=%d/tcp failed (errno: %d).\n", config.name, ip_address, config.nfacctd_bmp_port, errno); exit_all(1); } rc = listen(config.bmp_sock, 1); if (rc < 0) { Log(LOG_ERR, "ERROR ( %s/core/BMP ): listen() failed (errno: %d).\n", config.name, errno); exit_all(1); } /* Preparing for syncronous I/O multiplexing */ select_fd = 0; FD_ZERO(&bkp_read_descs); FD_SET(config.bmp_sock, &bkp_read_descs); { char srv_string[INET6_ADDRSTRLEN]; struct host_addr srv_addr; u_int16_t srv_port; sa_to_addr(&server, &srv_addr, &srv_port); addr_to_str(srv_string, &srv_addr); Log(LOG_INFO, "INFO ( %s/core/BMP ): waiting for BMP data on %s:%u\n", config.name, srv_string, srv_port); } /* Preparing ACL, if any */ if (config.nfacctd_bmp_allow_file) load_allow_file(config.nfacctd_bmp_allow_file, &allow); /* Let's initialize clean shared RIB */ for (afi = AFI_IP; afi < AFI_MAX; afi++) { for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { bmp_rib[afi][safi] = bgp_table_init(afi, safi); } } /* BMP peers batching checks */ if ((config.nfacctd_bmp_batch && !config.nfacctd_bmp_batch_interval) || (config.nfacctd_bmp_batch_interval && !config.nfacctd_bmp_batch)) { Log(LOG_WARNING, "WARN ( %s/core/BMP ): 'bmp_daemon_batch_interval' and 'bmp_daemon_batch' both set to zero.\n", config.name); config.nfacctd_bmp_batch = 0; config.nfacctd_bmp_batch_interval = 0; } if (!config.nfacctd_bmp_msglog_output && (config.nfacctd_bmp_msglog_file || config.nfacctd_bmp_msglog_amqp_routing_key)) #ifdef WITH_JANSSON config.nfacctd_bmp_msglog_output = PRINT_OUTPUT_JSON; #else Log(LOG_WARNING, "WARN ( %s/core/BMP ): bmp_daemon_msglog_output set to json but will produce no output (missing --enable-jansson).\n", config.name); #endif if (!config.bmp_dump_output && (config.bmp_dump_file || config.bmp_dump_amqp_routing_key)) #ifdef WITH_JANSSON config.bmp_dump_output = PRINT_OUTPUT_JSON; #else Log(LOG_WARNING, "WARN ( %s/core/BMP ): bmp_table_dump_output set to json but will produce no output (missing --enable-jansson).\n", config.name); #endif if (config.bmp_dump_file || config.bmp_dump_amqp_routing_key) { char dump_roundoff[] = "m"; time_t tmp_time; if (config.bmp_dump_refresh_time) { gettimeofday(&bmp_log_tstamp, NULL); dump_refresh_deadline = bmp_log_tstamp.tv_sec; tmp_time = roundoff_time(dump_refresh_deadline, dump_roundoff); while ((tmp_time+config.bmp_dump_refresh_time) < dump_refresh_deadline) { tmp_time += config.bmp_dump_refresh_time; } dump_refresh_deadline = tmp_time; dump_refresh_deadline += config.bmp_dump_refresh_time; /* it's a deadline not a basetime */ } else { config.bmp_dump_file = NULL; Log(LOG_WARNING, "WARN ( %s/core/BMP ): Invalid 'bmp_dump_refresh_time'.\n", config.name); } bmp_dump_init_amqp_host(); } for (;;) { select_again: select_fd = config.bmp_sock; for (peers_idx = 0; peers_idx < config.nfacctd_bmp_max_peers; peers_idx++) if (select_fd < bmp_peers[peers_idx].fd) select_fd = bmp_peers[peers_idx].fd; select_fd++; memcpy(&read_descs, &bkp_read_descs, sizeof(bkp_read_descs)); if (config.bmp_dump_file || config.bmp_dump_amqp_routing_key) { int delta; calc_refresh_timeout_sec(dump_refresh_deadline, bmp_log_tstamp.tv_sec, &delta); dump_refresh_timeout.tv_sec = delta; dump_refresh_timeout.tv_usec = 0; drt_ptr = &dump_refresh_timeout; } else drt_ptr = NULL; select_num = select(select_fd, &read_descs, NULL, NULL, drt_ptr); if (select_num < 0) goto select_again; if (reload_log_bmp_thread) { for (peers_idx = 0; peers_idx < config.nfacctd_bmp_max_peers; peers_idx++) { if (bmp_peers_log[peers_idx].fd) { fclose(bmp_peers_log[peers_idx].fd); bmp_peers_log[peers_idx].fd = open_logfile(bmp_peers_log[peers_idx].filename, "a"); } else break; } } if (config.nfacctd_bmp_msglog_file || config.nfacctd_bmp_msglog_amqp_routing_key || config.bmp_dump_file || config.bmp_dump_amqp_routing_key) { gettimeofday(&bmp_log_tstamp, NULL); compose_timestamp(bmp_log_tstamp_str, SRVBUFLEN, &bmp_log_tstamp, TRUE, config.sql_history_since_epoch); if (config.bmp_dump_file || config.bmp_dump_amqp_routing_key) { while (bmp_log_tstamp.tv_sec > dump_refresh_deadline) { bmp_handle_dump_event(); dump_refresh_deadline += config.bmp_dump_refresh_time; } } #ifdef WITH_RABBITMQ if (config.nfacctd_bmp_msglog_amqp_routing_key) { time_t last_fail = p_amqp_get_last_fail(&bmp_daemon_msglog_amqp_host); if (last_fail && ((last_fail + p_amqp_get_retry_interval(&bmp_daemon_msglog_amqp_host)) <= log_tstamp.tv_sec)) { bmp_daemon_msglog_init_amqp_host(); p_amqp_connect_to_publish(&bmp_daemon_msglog_amqp_host); } } #endif } /* If select_num == 0 then we got out of select() due to a timeout rather than because we had a message from a peeer to handle. By now we did all routine checks and can happily return to selet() again. */ if (!select_num) goto select_again; /* New connection is coming in */ if (FD_ISSET(config.bmp_sock, &read_descs)) { int peers_check_idx, peers_num; for (peer = NULL, peers_idx = 0; peers_idx < config.nfacctd_bmp_max_peers; peers_idx++) { if (bmp_peers[peers_idx].fd == 0) { now = time(NULL); if (bmp_current_batch_elem > 0 || now > (bmp_current_batch_stamp_base + config.nfacctd_bmp_batch_interval)) { peer = &bmp_peers[peers_idx]; if (bgp_peer_init(peer)) peer = NULL; log_notification_unset(&log_notifications.bmp_peers_throttling); if (config.nfacctd_bmp_batch && peer) { if (now > (bmp_current_batch_stamp_base + config.nfacctd_bmp_batch_interval)) { bmp_current_batch_elem = config.nfacctd_bmp_batch; bmp_current_batch_stamp_base = now; } if (bmp_current_batch_elem > 0) bmp_current_batch_elem--; } break; } else { /* throttle */ int fd = 0; /* We briefly accept the new connection to be able to drop it */ if (!log_notification_isset(log_notifications.bmp_peers_throttling)) { Log(LOG_INFO, "INFO ( %s/core/BMP ): throttling at BMP peer #%u\n", config.name, peers_idx); log_notification_set(&log_notifications.bmp_peers_throttling); } fd = accept(config.bmp_sock, (struct sockaddr *) &client, &clen); close(fd); goto select_again; } } } if (!peer) { int fd; /* We briefly accept the new connection to be able to drop it */ Log(LOG_ERR, "ERROR ( %s/core/BMP ): Insufficient number of BMP peers has been configured by 'bmp_daemon_max_peers' (%d).\n", config.name, config.nfacctd_bmp_max_peers); fd = accept(config.bmp_sock, (struct sockaddr *) &client, &clen); close(fd); goto select_again; } peer->fd = accept(config.bmp_sock, (struct sockaddr *) &client, &clen); #if defined ENABLE_IPV6 ipv4_mapped_to_ipv4(&client); #endif /* If an ACL is defined, here we check against and enforce it */ if (allow.num) allowed = check_allow(&allow, (struct sockaddr *)&client); else allowed = TRUE; if (!allowed) { bgp_peer_close(peer, FUNC_TYPE_BMP); goto select_again; } FD_SET(peer->fd, &bkp_read_descs); peer->addr.family = ((struct sockaddr *)&client)->sa_family; if (peer->addr.family == AF_INET) { peer->addr.address.ipv4.s_addr = ((struct sockaddr_in *)&client)->sin_addr.s_addr; peer->tcp_port = ntohs(((struct sockaddr_in *)&client)->sin_port); } #if defined ENABLE_IPV6 else if (peer->addr.family == AF_INET6) { memcpy(&peer->addr.address.ipv6, &((struct sockaddr_in6 *)&client)->sin6_addr, 16); peer->tcp_port = ntohs(((struct sockaddr_in6 *)&client)->sin6_port); } #endif addr_to_str(peer->addr_str, &peer->addr); memcpy(&peer->id, &peer->addr, sizeof(struct host_addr)); /* XXX: some inet_ntoa()'s could be around against peer->id */ if (config.nfacctd_bmp_msglog_file || config.nfacctd_bmp_msglog_amqp_routing_key) bgp_peer_log_init(peer, config.nfacctd_bmp_msglog_output, FUNC_TYPE_BMP); if (config.bmp_dump_file || config.bmp_dump_amqp_routing_key) bmp_dump_init_peer(peer); /* Check: only one TCP connection is allowed per peer */ for (peers_check_idx = 0, peers_num = 0; peers_check_idx < config.nfacctd_bmp_max_peers; peers_check_idx++) { if (peers_idx != peers_check_idx && !memcmp(&bmp_peers[peers_check_idx].addr, &peer->addr, sizeof(bmp_peers[peers_check_idx].addr))) { Log(LOG_ERR, "ERROR ( %s/core/BMP ): [Id: %s] Refusing new connection from existing peer.\n", config.name, bmp_peers[peers_check_idx].addr_str); FD_CLR(peer->fd, &bkp_read_descs); bgp_peer_close(peer, FUNC_TYPE_BMP); goto select_again; } else { if (bmp_peers[peers_check_idx].fd) peers_num++; } } Log(LOG_INFO, "INFO ( %s/core/BMP ): BMP peers usage: %u/%u\n", config.name, peers_num, config.nfacctd_bmp_max_peers); if (config.nfacctd_bmp_neighbors_file) write_neighbors_file(config.nfacctd_bmp_neighbors_file); goto select_again; } /* We have something coming in: let's lookup which peer is that; XXX old: to be optimized */ for (peer = NULL, peers_idx = 0; peers_idx < config.nfacctd_bmp_max_peers; peers_idx++) { if (bmp_peers[peers_idx].fd && FD_ISSET(bmp_peers[peers_idx].fd, &read_descs)) { peer = &bmp_peers[peers_idx]; break; } } if (!peer) { Log(LOG_ERR, "ERROR ( %s/core/BMP ): message delivered to an unknown peer (FD bits: %d; FD max: %d)\n", config.name, select_num, select_fd); goto select_again; } peer->msglen = ret = recv(peer->fd, bmp_packet, BMP_MAX_PACKET_SIZE, 0); if (ret <= 0) { Log(LOG_INFO, "INFO ( %s/core/BMP ): [Id: %s] Existing BMP connection was reset (%d).\n", config.name, peer->addr_str, errno); FD_CLR(peer->fd, &bkp_read_descs); bgp_peer_close(peer, FUNC_TYPE_BMP); goto select_again; } else bmp_process_packet(bmp_packet, peer->msglen, peer); } }
void skinny_isis_daemon() { char errbuf[PCAP_ERRBUF_SIZE]; struct pcap_device device; struct pcap_isis_callback_data cb_data; struct host_addr addr; struct prefix_ipv4 *ipv4; int index, ret; char area_tag[] = "default"; struct isis_area *area; struct isis_circuit *circuit; struct interface interface; memset(&device, 0, sizeof(struct pcap_device)); memset(&cb_data, 0, sizeof(cb_data)); memset(&interface, 0, sizeof(interface)); memset(&isis_spf_deadline, 0, sizeof(isis_spf_deadline)); /* initializing IS-IS structures */ isis_init(); dyn_cache_init(); /* thread master */ master = thread_master_create(); if (!config.nfacctd_isis_iface) { Log(LOG_ERR, "ERROR ( default/core/ISIS ): 'isis_daemon_iface' value is not specified. Terminating thread.\n"); exit(1); } if ((device.dev_desc = pcap_open_live(config.nfacctd_isis_iface, 65535, 0, 1000, errbuf)) == NULL) { Log(LOG_ERR, "ERROR ( default/core/ISIS ): pcap_open_live(): %s\n", errbuf); exit(1); } device.link_type = pcap_datalink(device.dev_desc); for (index = 0; _isis_devices[index].link_type != -1; index++) { if (device.link_type == _isis_devices[index].link_type) device.data = &_isis_devices[index]; } if (device.data == NULL) { Log(LOG_ERR, "ERROR ( default/core/ISIS ): data link not supported: %d\n", device.link_type); return; } else { Log(LOG_INFO, "OK ( default/core/ISIS ): link type is: %d\n", device.link_type); cb_data.device = &device; } area = isis_area_create(); area->area_tag = area_tag; area->is_type = IS_LEVEL_2; area->newmetric = TRUE; listnode_add(isis->area_list, area); Log(LOG_DEBUG, "DEBUG ( default/core/ISIS ): New IS-IS area instance %s\n", area->area_tag); if (config.nfacctd_isis_net) area_net_title(area, config.nfacctd_isis_net); else { Log(LOG_ERR, "ERROR ( default/core/ISIS ): 'isis_daemon_net' value is not specified. Terminating thread.\n"); exit_all(1); } circuit = isis_circuit_new(); circuit->circ_type = CIRCUIT_T_P2P; circuit->fd = pcap_fileno(device.dev_desc); circuit->tx = isis_send_pdu_p2p; circuit->interface = &interface; circuit->state = C_STATE_UP; if (config.nfacctd_isis_ip) { trim_spaces(config.nfacctd_isis_ip); ret = str_to_addr(config.nfacctd_isis_ip, &addr); if (!ret) { Log(LOG_ERR, "ERROR ( default/core/ISIS ): 'isis_daemon_ip' value is not a valid IPv4/IPv6 address. Terminating thread.\n"); exit_all(1); } } else { Log(LOG_ERR, "ERROR ( default/core/ISIS ): 'isis_daemon_ip' value is not specified. Terminating thread.\n"); exit_all(1); } circuit->ip_router = addr.address.ipv4.s_addr; ipv4 = isis_prefix_ipv4_new(); ipv4->prefixlen = 32; ipv4->prefix.s_addr = addr.address.ipv4.s_addr; circuit->ip_addrs = list_new(); listnode_add(circuit->ip_addrs, ipv4); circuit_update_nlpids(circuit); isis_circuit_configure(circuit, area); cb_data.circuit = circuit; area->ip_circuits = 1; memcpy(circuit->interface->name, config.nfacctd_isis_iface, strlen(config.nfacctd_isis_iface)); circuit->interface->ifindex = if_nametoindex(config.nfacctd_isis_iface); if (!config.nfacctd_isis_mtu) config.nfacctd_isis_mtu = SNAPLEN_ISIS_DEFAULT; for (;;) { /* XXX: should get a select() here at some stage? */ pcap_loop(device.dev_desc, -1, isis_pdu_runner, (u_char *) &cb_data); break; } pcap_close(device.dev_desc); }
void skinny_bmp_daemon() { int slen, clen, ret, rc, peers_idx, allowed, yes=1, no=0; int peers_idx_rr = 0, max_peers_idx = 0; u_int32_t pkt_remaining_len=0; time_t now; afi_t afi; safi_t safi; struct bmp_peer *bmpp = NULL; struct bgp_peer *peer = NULL; #if defined ENABLE_IPV6 struct sockaddr_storage server, client; #else struct sockaddr server, client; #endif struct hosts_table allow; struct host_addr addr; struct bgp_peer_batch bp_batch; /* select() stuff */ fd_set read_descs, bkp_read_descs; int fd, select_fd, bkp_select_fd, recalc_fds, select_num; /* logdump time management */ time_t dump_refresh_deadline; struct timeval dump_refresh_timeout, *drt_ptr; /* initial cleanups */ reload_map_bmp_thread = FALSE; reload_log_bmp_thread = FALSE; memset(&server, 0, sizeof(server)); memset(&client, 0, sizeof(client)); memset(&allow, 0, sizeof(struct hosts_table)); clen = sizeof(client); bmp_routing_db = &inter_domain_routing_dbs[FUNC_TYPE_BMP]; memset(bmp_routing_db, 0, sizeof(struct bgp_rt_structs)); /* socket creation for BMP server: IPv4 only */ #if (defined ENABLE_IPV6) if (!config.nfacctd_bmp_ip) { struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&server; sa6->sin6_family = AF_INET6; sa6->sin6_port = htons(config.nfacctd_bmp_port); slen = sizeof(struct sockaddr_in6); } #else if (!config.nfacctd_bmp_ip) { struct sockaddr_in *sa4 = (struct sockaddr_in *)&server; sa4->sin_family = AF_INET; sa4->sin_addr.s_addr = htonl(0); sa4->sin_port = htons(config.nfacctd_bmp_port); slen = sizeof(struct sockaddr_in); } #endif else { trim_spaces(config.nfacctd_bmp_ip); ret = str_to_addr(config.nfacctd_bmp_ip, &addr); if (!ret) { Log(LOG_ERR, "ERROR ( %s/%s ): 'bmp_daemon_ip' value is not a valid IPv4/IPv6 address. Terminating thread.\n", config.name, bmp_misc_db->log_str); exit_all(1); } slen = addr_to_sa((struct sockaddr *)&server, &addr, config.nfacctd_bmp_port); } if (!config.nfacctd_bmp_max_peers) config.nfacctd_bmp_max_peers = BMP_MAX_PEERS_DEFAULT; Log(LOG_INFO, "INFO ( %s/%s ): maximum BMP peers allowed: %d\n", config.name, bmp_misc_db->log_str, config.nfacctd_bmp_max_peers); bmp_peers = malloc(config.nfacctd_bmp_max_peers*sizeof(struct bmp_peer)); if (!bmp_peers) { Log(LOG_ERR, "ERROR ( %s/%s ): Unable to malloc() BMP peers structure. Terminating thread.\n", config.name, bmp_misc_db->log_str); exit_all(1); } memset(bmp_peers, 0, config.nfacctd_bmp_max_peers*sizeof(struct bmp_peer)); if (config.nfacctd_bmp_msglog_file || config.nfacctd_bmp_msglog_amqp_routing_key || config.nfacctd_bmp_msglog_kafka_topic) { if (config.nfacctd_bmp_msglog_file) bmp_misc_db->msglog_backend_methods++; if (config.nfacctd_bmp_msglog_amqp_routing_key) bmp_misc_db->msglog_backend_methods++; if (config.nfacctd_bmp_msglog_kafka_topic) bmp_misc_db->msglog_backend_methods++; if (bmp_misc_db->msglog_backend_methods > 1) { Log(LOG_ERR, "ERROR ( %s/%s ): bmp_daemon_msglog_file, bmp_daemon_msglog_amqp_routing_key and bmp_daemon_msglog_kafka_topic are mutually exclusive. Terminating thread.\n", config.name, bmp_misc_db->log_str); exit_all(1); } } if (config.bmp_dump_file || config.bmp_dump_amqp_routing_key || config.bmp_dump_kafka_topic) { if (config.bmp_dump_file) bmp_misc_db->dump_backend_methods++; if (config.bmp_dump_amqp_routing_key) bmp_misc_db->dump_backend_methods++; if (config.bmp_dump_kafka_topic) bmp_misc_db->dump_backend_methods++; if (bmp_misc_db->dump_backend_methods > 1) { Log(LOG_ERR, "ERROR ( %s/%s ): bmp_dump_file, bmp_dump_amqp_routing_key and bmp_dump_kafka_topic are mutually exclusive. Terminating thread.\n", config.name, bmp_misc_db->log_str); exit_all(1); } } if (bmp_misc_db->msglog_backend_methods || bmp_misc_db->dump_backend_methods) bgp_peer_log_seq_init(&bmp_misc_db->log_seq); if (bmp_misc_db->msglog_backend_methods) { bmp_misc_db->peers_log = malloc(config.nfacctd_bmp_max_peers*sizeof(struct bgp_peer_log)); if (!bmp_misc_db->peers_log) { Log(LOG_ERR, "ERROR ( %s/%s ): Unable to malloc() BMP peers log structure. Terminating thread.\n", config.name, bmp_misc_db->log_str); exit_all(1); } memset(bmp_misc_db->peers_log, 0, config.nfacctd_bmp_max_peers*sizeof(struct bgp_peer_log)); if (config.nfacctd_bmp_msglog_amqp_routing_key) { #ifdef WITH_RABBITMQ bmp_daemon_msglog_init_amqp_host(); p_amqp_connect_to_publish(&bmp_daemon_msglog_amqp_host); if (!config.nfacctd_bmp_msglog_amqp_retry) config.nfacctd_bmp_msglog_amqp_retry = AMQP_DEFAULT_RETRY; #else Log(LOG_WARNING, "WARN ( %s/%s ): p_amqp_connect_to_publish() not possible due to missing --enable-rabbitmq\n", config.name, bmp_misc_db->log_str); #endif } if (config.nfacctd_bmp_msglog_kafka_topic) { #ifdef WITH_KAFKA bmp_daemon_msglog_init_kafka_host(); #else Log(LOG_WARNING, "WARN ( %s/%s ): p_kafka_connect_to_produce() not possible due to missing --enable-kafka\n", config.name, bmp_misc_db->log_str); #endif } } if (!config.bmp_table_attr_hash_buckets) config.bmp_table_attr_hash_buckets = HASHTABSIZE; bgp_attr_init(config.bmp_table_attr_hash_buckets, bmp_routing_db); if (!config.bmp_table_peer_buckets) config.bmp_table_peer_buckets = DEFAULT_BGP_INFO_HASH; if (!config.bmp_table_per_peer_buckets) config.bmp_table_per_peer_buckets = DEFAULT_BGP_INFO_PER_PEER_HASH; if (config.bmp_table_per_peer_hash == BGP_ASPATH_HASH_PATHID) bmp_route_info_modulo = bmp_route_info_modulo_pathid; else { Log(LOG_ERR, "ERROR ( %s/%s ): Unknown 'bmp_table_per_peer_hash' value. Terminating thread.\n", config.name, bmp_misc_db->log_str); exit_all(1); } config.bmp_sock = socket(((struct sockaddr *)&server)->sa_family, SOCK_STREAM, 0); if (config.bmp_sock < 0) { #if (defined ENABLE_IPV6) /* retry with IPv4 */ if (!config.nfacctd_bmp_ip) { struct sockaddr_in *sa4 = (struct sockaddr_in *)&server; sa4->sin_family = AF_INET; sa4->sin_addr.s_addr = htonl(0); sa4->sin_port = htons(config.nfacctd_bmp_port); slen = sizeof(struct sockaddr_in); config.bmp_sock = socket(((struct sockaddr *)&server)->sa_family, SOCK_STREAM, 0); } #endif if (config.bmp_sock < 0) { Log(LOG_ERR, "ERROR ( %s/%s ): thread socket() failed. Terminating thread.\n", config.name, bmp_misc_db->log_str); exit_all(1); } } if (config.nfacctd_bmp_ipprec) { int opt = config.nfacctd_bmp_ipprec << 5; rc = setsockopt(config.bmp_sock, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)); if (rc < 0) Log(LOG_ERR, "WARN ( %s/%s ): setsockopt() failed for IP_TOS (errno: %d).\n", config.name, bmp_misc_db->log_str, errno); } rc = setsockopt(config.bmp_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)); if (rc < 0) Log(LOG_ERR, "WARN ( %s/%s ): setsockopt() failed for SO_REUSEADDR (errno: %d).\n", config.name, bmp_misc_db->log_str, errno); #if (defined ENABLE_IPV6) && (defined IPV6_BINDV6ONLY) rc = setsockopt(config.bmp_sock, IPPROTO_IPV6, IPV6_BINDV6ONLY, (char *) &no, (socklen_t) sizeof(no)); if (rc < 0) Log(LOG_ERR, "WARN ( %s/%s ): setsockopt() failed for IPV6_BINDV6ONLY (errno: %d).\n", config.name, bmp_misc_db->log_str, errno); #endif if (config.nfacctd_bmp_pipe_size) { int l = sizeof(config.nfacctd_bmp_pipe_size); int saved = 0, obtained = 0; getsockopt(config.bmp_sock, SOL_SOCKET, SO_RCVBUF, &saved, &l); Setsocksize(config.bmp_sock, SOL_SOCKET, SO_RCVBUF, &config.nfacctd_bmp_pipe_size, sizeof(config.nfacctd_bmp_pipe_size)); getsockopt(config.bmp_sock, SOL_SOCKET, SO_RCVBUF, &obtained, &l); Setsocksize(config.bmp_sock, SOL_SOCKET, SO_RCVBUF, &saved, l); getsockopt(config.bmp_sock, SOL_SOCKET, SO_RCVBUF, &obtained, &l); Log(LOG_INFO, "INFO ( %s/%s ): bmp_daemon_pipe_size: obtained=%d target=%d.\n", config.name, bmp_misc_db->log_str, obtained, config.nfacctd_bmp_pipe_size); } rc = bind(config.bmp_sock, (struct sockaddr *) &server, slen); if (rc < 0) { char null_ip_address[] = "0.0.0.0"; char *ip_address; ip_address = config.nfacctd_bmp_ip ? config.nfacctd_bmp_ip : null_ip_address; Log(LOG_ERR, "ERROR ( %s/%s ): bind() to ip=%s port=%d/tcp failed (errno: %d).\n", config.name, bmp_misc_db->log_str, ip_address, config.nfacctd_bmp_port, errno); exit_all(1); } rc = listen(config.bmp_sock, 1); if (rc < 0) { Log(LOG_ERR, "ERROR ( %s/%s ): listen() failed (errno: %d).\n", config.name, bmp_misc_db->log_str, errno); exit_all(1); } /* Preparing for syncronous I/O multiplexing */ select_fd = 0; FD_ZERO(&bkp_read_descs); FD_SET(config.bmp_sock, &bkp_read_descs); { char srv_string[INET6_ADDRSTRLEN]; struct host_addr srv_addr; u_int16_t srv_port; sa_to_addr((struct sockaddr *)&server, &srv_addr, &srv_port); addr_to_str(srv_string, &srv_addr); Log(LOG_INFO, "INFO ( %s/%s ): waiting for BMP data on %s:%u\n", config.name, bmp_misc_db->log_str, srv_string, srv_port); } /* Preparing ACL, if any */ if (config.nfacctd_bmp_allow_file) load_allow_file(config.nfacctd_bmp_allow_file, &allow); /* Let's initialize clean shared RIB */ for (afi = AFI_IP; afi < AFI_MAX; afi++) { for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { bmp_routing_db->rib[afi][safi] = bgp_table_init(afi, safi); } } /* BMP peers batching checks */ if ((config.nfacctd_bmp_batch && !config.nfacctd_bmp_batch_interval) || (config.nfacctd_bmp_batch_interval && !config.nfacctd_bmp_batch)) { Log(LOG_WARNING, "WARN ( %s/%s ): 'bmp_daemon_batch_interval' and 'bmp_daemon_batch' both set to zero.\n", config.name, bmp_misc_db->log_str); config.nfacctd_bmp_batch = 0; config.nfacctd_bmp_batch_interval = 0; } else bgp_batch_init(&bp_batch, config.nfacctd_bmp_batch, config.nfacctd_bmp_batch_interval); if (bmp_misc_db->msglog_backend_methods) { #ifdef WITH_JANSSON if (!config.nfacctd_bmp_msglog_output) config.nfacctd_bmp_msglog_output = PRINT_OUTPUT_JSON; #else Log(LOG_WARNING, "WARN ( %s/%s ): bmp_daemon_msglog_output set to json but will produce no output (missing --enable-jansson).\n", config.name, bmp_misc_db->log_str); #endif } if (bmp_misc_db->dump_backend_methods) { #ifdef WITH_JANSSON if (!config.bmp_dump_output) config.bmp_dump_output = PRINT_OUTPUT_JSON; #else Log(LOG_WARNING, "WARN ( %s/%s ): bmp_table_dump_output set to json but will produce no output (missing --enable-jansson).\n", config.name, bmp_misc_db->log_str); #endif } if (bmp_misc_db->dump_backend_methods) { char dump_roundoff[] = "m"; time_t tmp_time; if (config.bmp_dump_refresh_time) { gettimeofday(&bmp_misc_db->log_tstamp, NULL); dump_refresh_deadline = bmp_misc_db->log_tstamp.tv_sec; tmp_time = roundoff_time(dump_refresh_deadline, dump_roundoff); while ((tmp_time+config.bmp_dump_refresh_time) < dump_refresh_deadline) { tmp_time += config.bmp_dump_refresh_time; } dump_refresh_deadline = tmp_time; dump_refresh_deadline += config.bmp_dump_refresh_time; /* it's a deadline not a basetime */ } else { config.bmp_dump_file = NULL; bmp_misc_db->dump_backend_methods = FALSE; Log(LOG_WARNING, "WARN ( %s/%s ): Invalid 'bmp_dump_refresh_time'.\n", config.name, bmp_misc_db->log_str); } if (config.bmp_dump_amqp_routing_key) bmp_dump_init_amqp_host(); if (config.bmp_dump_kafka_topic) bmp_dump_init_kafka_host(); } select_fd = bkp_select_fd = (config.bmp_sock + 1); recalc_fds = FALSE; bmp_link_misc_structs(bmp_misc_db); for (;;) { select_again: if (recalc_fds) { select_fd = config.bmp_sock; max_peers_idx = -1; /* .. since valid indexes include 0 */ for (peers_idx = 0; peers_idx < config.nfacctd_bmp_max_peers; peers_idx++) { if (select_fd < bmp_peers[peers_idx].self.fd) select_fd = bmp_peers[peers_idx].self.fd; if (bmp_peers[peers_idx].self.fd) max_peers_idx = peers_idx; } select_fd++; max_peers_idx++; bkp_select_fd = select_fd; recalc_fds = FALSE; } else select_fd = bkp_select_fd; memcpy(&read_descs, &bkp_read_descs, sizeof(bkp_read_descs)); if (bmp_misc_db->dump_backend_methods) { int delta; calc_refresh_timeout_sec(dump_refresh_deadline, bmp_misc_db->log_tstamp.tv_sec, &delta); dump_refresh_timeout.tv_sec = delta; dump_refresh_timeout.tv_usec = 0; drt_ptr = &dump_refresh_timeout; } else drt_ptr = NULL; select_num = select(select_fd, &read_descs, NULL, NULL, drt_ptr); if (select_num < 0) goto select_again; if (reload_map_bmp_thread) { if (config.nfacctd_bmp_allow_file) load_allow_file(config.nfacctd_bmp_allow_file, &allow); reload_map_bmp_thread = FALSE; } if (reload_log_bmp_thread) { for (peers_idx = 0; peers_idx < config.nfacctd_bmp_max_peers; peers_idx++) { if (bmp_misc_db->peers_log[peers_idx].fd) { fclose(bmp_misc_db->peers_log[peers_idx].fd); bmp_misc_db->peers_log[peers_idx].fd = open_output_file(bmp_misc_db->peers_log[peers_idx].filename, "a", FALSE); setlinebuf(bmp_misc_db->peers_log[peers_idx].fd); } else break; } reload_log_bmp_thread = FALSE; } if (bmp_misc_db->msglog_backend_methods || bmp_misc_db->dump_backend_methods) { gettimeofday(&bmp_misc_db->log_tstamp, NULL); compose_timestamp(bmp_misc_db->log_tstamp_str, SRVBUFLEN, &bmp_misc_db->log_tstamp, TRUE, config.timestamps_since_epoch, config.timestamps_rfc3339, config.timestamps_utc); if (bmp_misc_db->dump_backend_methods) { while (bmp_misc_db->log_tstamp.tv_sec > dump_refresh_deadline) { bmp_misc_db->dump.tstamp.tv_sec = dump_refresh_deadline; bmp_misc_db->dump.tstamp.tv_usec = 0; compose_timestamp(bmp_misc_db->dump.tstamp_str, SRVBUFLEN, &bmp_misc_db->dump.tstamp, FALSE, config.timestamps_since_epoch, config.timestamps_rfc3339, config.timestamps_utc); bmp_misc_db->dump.period = config.bmp_dump_refresh_time; bmp_handle_dump_event(); dump_refresh_deadline += config.bmp_dump_refresh_time; } } #ifdef WITH_RABBITMQ if (config.nfacctd_bmp_msglog_amqp_routing_key) { time_t last_fail = P_broker_timers_get_last_fail(&bmp_daemon_msglog_amqp_host.btimers); if (last_fail && ((last_fail + P_broker_timers_get_retry_interval(&bmp_daemon_msglog_amqp_host.btimers)) <= bmp_misc_db->log_tstamp.tv_sec)) { bmp_daemon_msglog_init_amqp_host(); p_amqp_connect_to_publish(&bmp_daemon_msglog_amqp_host); } } #endif #ifdef WITH_KAFKA if (config.nfacctd_bmp_msglog_kafka_topic) { time_t last_fail = P_broker_timers_get_last_fail(&bmp_daemon_msglog_kafka_host.btimers); if (last_fail && ((last_fail + P_broker_timers_get_retry_interval(&bmp_daemon_msglog_kafka_host.btimers)) <= bmp_misc_db->log_tstamp.tv_sec)) bmp_daemon_msglog_init_kafka_host(); } #endif } /* If select_num == 0 then we got out of select() due to a timeout rather than because we had a message from a peer to handle. By now we did all routine checks and can happily return to select() again. */ if (!select_num) goto select_again; /* New connection is coming in */ if (FD_ISSET(config.bmp_sock, &read_descs)) { int peers_check_idx, peers_num; fd = accept(config.bmp_sock, (struct sockaddr *) &client, &clen); if (fd == ERR) goto read_data; #if defined ENABLE_IPV6 ipv4_mapped_to_ipv4(&client); #endif /* If an ACL is defined, here we check against and enforce it */ if (allow.num) allowed = check_allow(&allow, (struct sockaddr *)&client); else allowed = TRUE; if (!allowed) { close(fd); goto read_data; } for (peer = NULL, peers_idx = 0; peers_idx < config.nfacctd_bmp_max_peers; peers_idx++) { if (!bmp_peers[peers_idx].self.fd) { now = time(NULL); /* Admitted if: * batching feature is disabled or * we have room in the current batch or * we can start a new batch */ if (bgp_batch_is_admitted(&bp_batch, now)) { peer = &bmp_peers[peers_idx].self; bmpp = &bmp_peers[peers_idx]; if (bmp_peer_init(bmpp, FUNC_TYPE_BMP)) { peer = NULL; bmpp = NULL; } else recalc_fds = TRUE; log_notification_unset(&log_notifications.bgp_peers_throttling); if (bgp_batch_is_enabled(&bp_batch) && peer) { if (bgp_batch_is_expired(&bp_batch, now)) bgp_batch_reset(&bp_batch, now); if (bgp_batch_is_not_empty(&bp_batch)) bgp_batch_decrease_counter(&bp_batch); } break; } else { /* throttle */ /* We briefly accept the new connection to be able to drop it */ if (!log_notification_isset(&log_notifications.bmp_peers_throttling, now)) { Log(LOG_INFO, "INFO ( %s/%s ): throttling at BMP peer #%u\n", config.name, bmp_misc_db->log_str, peers_idx); log_notification_set(&log_notifications.bmp_peers_throttling, now, FALSE); } close(fd); goto read_data; } } } if (!peer) { int fd; /* We briefly accept the new connection to be able to drop it */ Log(LOG_ERR, "ERROR ( %s/%s ): Insufficient number of BMP peers has been configured by 'bmp_daemon_max_peers' (%d).\n", config.name, bmp_misc_db->log_str, config.nfacctd_bmp_max_peers); close(fd); goto read_data; } peer->fd = fd; FD_SET(peer->fd, &bkp_read_descs); peer->addr.family = ((struct sockaddr *)&client)->sa_family; if (peer->addr.family == AF_INET) { peer->addr.address.ipv4.s_addr = ((struct sockaddr_in *)&client)->sin_addr.s_addr; peer->tcp_port = ntohs(((struct sockaddr_in *)&client)->sin_port); } #if defined ENABLE_IPV6 else if (peer->addr.family == AF_INET6) { memcpy(&peer->addr.address.ipv6, &((struct sockaddr_in6 *)&client)->sin6_addr, 16); peer->tcp_port = ntohs(((struct sockaddr_in6 *)&client)->sin6_port); } #endif addr_to_str(peer->addr_str, &peer->addr); memcpy(&peer->id, &peer->addr, sizeof(struct host_addr)); /* XXX: some inet_ntoa()'s could be around against peer->id */ if (bmp_misc_db->msglog_backend_methods) bgp_peer_log_init(peer, config.nfacctd_bmp_msglog_output, FUNC_TYPE_BMP); if (bmp_misc_db->dump_backend_methods) bmp_dump_init_peer(peer); /* Check: multiple TCP connections per peer */ for (peers_check_idx = 0, peers_num = 0; peers_check_idx < config.nfacctd_bmp_max_peers; peers_check_idx++) { if (peers_idx != peers_check_idx && !memcmp(&bmp_peers[peers_check_idx].self.addr, &peer->addr, sizeof(bmp_peers[peers_check_idx].self.addr))) { if (bmp_misc_db->is_thread && !config.nfacctd_bgp_to_agent_map) { Log(LOG_WARNING, "WARN ( %s/%s ): [%s] Multiple connections from peer and no bgp_agent_map defined.\n", config.name, bmp_misc_db->log_str, bmp_peers[peers_check_idx].self.addr_str); } } else { if (bmp_peers[peers_check_idx].self.fd) peers_num++; } } Log(LOG_INFO, "INFO ( %s/%s ): [%s] BMP peers usage: %u/%u\n", config.name, bmp_misc_db->log_str, peer->addr_str, peers_num, config.nfacctd_bmp_max_peers); } read_data: /* We have something coming in: let's lookup which peer is that. FvD: To avoid starvation of the "later established" peers, we offset the start of the search in a round-robin style. */ for (peer = NULL, peers_idx = 0; peers_idx < max_peers_idx; peers_idx++) { int loc_idx = (peers_idx + peers_idx_rr) % max_peers_idx; if (bmp_peers[loc_idx].self.fd && FD_ISSET(bmp_peers[loc_idx].self.fd, &read_descs)) { peer = &bmp_peers[loc_idx].self; bmpp = &bmp_peers[loc_idx]; peers_idx_rr = (peers_idx_rr + 1) % max_peers_idx; break; } } if (!peer) goto select_again; ret = recv(peer->fd, &peer->buf.base[peer->buf.truncated_len], (peer->buf.len - peer->buf.truncated_len), 0); peer->msglen = (ret + peer->buf.truncated_len); if (ret <= 0) { Log(LOG_INFO, "INFO ( %s/%s ): [%s] BMP connection reset by peer (%d).\n", config.name, bmp_misc_db->log_str, peer->addr_str, errno); FD_CLR(peer->fd, &bkp_read_descs); bmp_peer_close(bmpp, FUNC_TYPE_BMP); recalc_fds = TRUE; goto select_again; } else { pkt_remaining_len = bmp_process_packet(peer->buf.base, peer->msglen, bmpp); /* handling offset for TCP segment reassembly */ if (pkt_remaining_len) peer->buf.truncated_len = bmp_packet_adj_offset(peer->buf.base, peer->buf.len, peer->msglen, pkt_remaining_len, peer->addr_str); else peer->buf.truncated_len = 0; } } }