void do_resend() { struct resend *resend; resend = to_resend; while(resend) { if(!resend_expired(resend) && resend->delay > 0 && resend->max > 0) { struct timeval timeout; timeval_add_msec(&timeout, &resend->time, resend->delay); if(timeval_compare(&now, &timeout) >= 0) { switch(resend->kind) { case RESEND_REQUEST: send_multihop_request(resend->ifp, resend->prefix, resend->plen, resend->src_prefix, resend->src_plen, resend->seqno, resend->id, 127); break; case RESEND_UPDATE: send_update(resend->ifp, 1, resend->prefix, resend->plen, resend->src_prefix, resend->src_plen); break; default: abort(); } resend->delay = MIN(0xFFFF, resend->delay * 2); resend->max--; } } resend = resend->next; } recompute_resend_time(); }
void recompute_resend_time() { struct resend *request; struct timeval resend = {0, 0}; request = to_resend; while(request) { if(!resend_expired(request) && request->delay > 0 && request->max > 0) { struct timeval timeout; timeval_add_msec(&timeout, &request->time, request->delay); timeval_min(&resend, &timeout); } request = request->next; } resend_time = resend; }
/* We got a Hello or IHU from a neighbour, update its entry. */ int update_neighbour(struct in6_addr *from, struct interface *interface, unsigned int ihu, unsigned short interval_or_rxcost) { int i = find_neighbour(interface, from, !ihu); if(i < 0) return 0; if(ihu) { neighbours[i].rxcost = interval_or_rxcost; } else { struct timeval now; int interval = interval_or_rxcost; gettime(&now); /* We'll expire this neighbour if we miss 3 Hellos in a row. */ timeval_add_msec(&neighbours[i].timeout, &now, 3 * interval * 10 + rand() % (interval * 5)); } return 1; }
/* We just got an Update for the default route. */ int update_selected_route(struct interface *interface, struct in6_addr *nexthop, short interval, int metric) { struct timeval now; int n = find_neighbour(interface, nexthop, 0); if(n < 0) return 0; metric += MAX(link_cost, neighbours[n].rxcost); gettime(&now); if(selected_nexthop_metric >= INFINITY || interface != selected_interface || memcmp(nexthop, &selected_nexthop, sizeof(selected_nexthop)) != 0) { int rc; if(metric >= INFINITY || (metric >= selected_nexthop_metric + 32 && timeval_compare(&now, &selected_nexthop_timeout) < 0)) { /* Our currently selected route is just as good or better. */ return 0; } rc = install_default_route(interface->ifindex, nexthop); if(rc < 0) { perror("install_default_route"); return -1; } selected_interface = interface; memcpy(&selected_nexthop, nexthop, sizeof(selected_nexthop)); } selected_nexthop_metric = metric; /* Expire this route when we lose 3 updates in a row. */ timeval_add_msec(&selected_nexthop_timeout, &now, 3 * interval * 10 + rand() % (interval * 5)); return 1; }
static void *helper_thread_main(void *data) { struct helper_data *hd = data; unsigned int msec_to_next_event, next_log; struct timeval tv, last_du; int ret = 0; sk_out_assign(hd->sk_out); gettimeofday(&tv, NULL); memcpy(&last_du, &tv, sizeof(tv)); fio_mutex_up(hd->startup_mutex); msec_to_next_event = DISK_UTIL_MSEC; while (!ret && !hd->exit) { struct timespec ts; struct timeval now; uint64_t since_du; timeval_add_msec(&tv, msec_to_next_event); ts.tv_sec = tv.tv_sec; ts.tv_nsec = tv.tv_usec * 1000; pthread_mutex_lock(&hd->lock); pthread_cond_timedwait(&hd->cond, &hd->lock, &ts); gettimeofday(&now, NULL); if (hd->reset) { memcpy(&tv, &now, sizeof(tv)); memcpy(&last_du, &now, sizeof(last_du)); hd->reset = 0; } pthread_mutex_unlock(&hd->lock); since_du = mtime_since(&last_du, &now); if (since_du >= DISK_UTIL_MSEC || DISK_UTIL_MSEC - since_du < 10) { ret = update_io_ticks(); timeval_add_msec(&last_du, DISK_UTIL_MSEC); msec_to_next_event = DISK_UTIL_MSEC; if (since_du >= DISK_UTIL_MSEC) msec_to_next_event -= (since_du - DISK_UTIL_MSEC); } else { if (since_du >= DISK_UTIL_MSEC) msec_to_next_event = DISK_UTIL_MSEC - (DISK_UTIL_MSEC - since_du); else msec_to_next_event = DISK_UTIL_MSEC; } if (hd->do_stat) { hd->do_stat = 0; __show_running_run_stats(); } next_log = calc_log_samples(); if (!next_log) next_log = DISK_UTIL_MSEC; msec_to_next_event = min(next_log, msec_to_next_event); if (!is_backend) print_thread_status(); } fio_writeout_logs(false); sk_out_drop(); return NULL; }
int record_resend(int kind, const unsigned char *prefix, unsigned char plen, const unsigned char *src_prefix, unsigned char src_plen, unsigned short seqno, const unsigned char *id, struct interface *ifp, int delay) { struct resend *resend; unsigned int ifindex = ifp ? ifp->ifindex : 0; if((kind == RESEND_REQUEST && input_filter(NULL, prefix, plen, src_prefix, src_plen, NULL, ifindex) >= INFINITY) || (kind == RESEND_UPDATE && output_filter(NULL, prefix, plen, src_prefix, src_plen, ifindex) >= INFINITY)) return 0; if(delay >= 0xFFFF) delay = 0xFFFF; resend = find_resend(kind, prefix, plen, src_prefix, src_plen, NULL); if(resend) { if(resend->delay && delay) resend->delay = MIN(resend->delay, delay); else if(delay) resend->delay = delay; resend->time = now; resend->max = RESEND_MAX; if(id && memcmp(resend->id, id, 8) == 0 && seqno_compare(resend->seqno, seqno) > 0) { return 0; } if(id) memcpy(resend->id, id, 8); else memset(resend->id, 0, 8); resend->seqno = seqno; if(resend->ifp != ifp) resend->ifp = NULL; } else { resend = calloc(1, sizeof(struct resend)); if(resend == NULL) return -1; resend->kind = kind; resend->max = RESEND_MAX; resend->delay = delay; memcpy(resend->prefix, prefix, 16); resend->plen = plen; memcpy(resend->src_prefix, src_prefix, 16); resend->src_plen = src_plen; resend->seqno = seqno; if(id) memcpy(resend->id, id, 8); resend->ifp = ifp; resend->time = now; resend->next = to_resend; to_resend = resend; } if(resend->delay) { struct timeval timeout; timeval_add_msec(&timeout, &resend->time, resend->delay); timeval_min(&resend_time, &timeout); } return 1; }
void set_timeout(struct timeval *timeout, int msecs) { timeval_add_msec(timeout, &now, roughly(msecs)); }
int main(int argc, char **argv) { int i, opt, rc; int sock; struct timeval now; gettime(&now); inet_pton(AF_INET6, "ff02::1:6", &babel_group); babel_port = 6696; srand(now.tv_sec ^ now.tv_usec); while(1) { opt = getopt(argc, argv, "p:u:h:c:"); if(opt < 0) break; switch(opt) { case 'p': /* prefix */ if(have_prefix) goto usage; rc = inet_pton(AF_INET6, optarg, &myprefix); if(rc != 1) goto usage; have_prefix = 1; break; case 'u': /* update interval */ update_interval = atoi(optarg); if(update_interval <= 0) goto usage; break; case 'h': /* hello interval */ hello_interval = atoi(optarg); if(hello_interval <= 0) goto usage; break; case 'c': /* link cost */ link_cost = atoi(optarg); if(link_cost <= 0) goto usage; break; default: goto usage; } } if(!have_prefix) fprintf(stderr, "Warning: you didn't ask me to announce a prefix.\n"); if(argc - optind > MAXINTERFACES) { fprintf(stderr, "Too many interfaces.\n"); exit(1); } for(i = 0; i < argc - optind; i++) { int index; index = if_nametoindex(argv[optind + i]); if(index <= 0) { fprintf(stderr, "Unknown interface %s\n", argv[i]); exit(1); } memset(&interfaces[i], 0, sizeof(interfaces[i])); interfaces[i].ifindex = index; interfaces[i].ifname = argv[optind + i]; rc = get_local_address(interfaces[i].ifindex, &interfaces[i].address); if(rc < 0) { perror("get_local_address"); fprintf(stderr, "Continuing anyway -- " "won't perform reachibility detection " "on interface %s.\n", interfaces[i].ifname); } interfaces[i].seqno = rand() & 0xFFFF; } numinterfaces = argc - optind; random_eui64(my_router_id); myseqno = rand() & 0xFFFF; sock = babel_socket(babel_port); if(sock < 0) { perror("babel_socket"); exit(1); } for(i = 0; i < numinterfaces; i++) { rc = join_group(sock, interfaces[i].ifindex, &babel_group); if(rc < 0) { perror("setsockopt(IPV6_JOIN_GROUP)"); exit(1); } } catch_signals(sigexit); while(!exiting) { struct sockaddr_in6 sin6; unsigned char buf[BUF_SIZE]; struct timeval tv, update, zerotv = {0, 0}; fd_set readfds; int hello_count = 0; /* Compute when to wake up. */ gettime(&now); timeval_add_msec(&tv, &last_hello, hello_interval * 700 + rand() % 300); timeval_add_msec(&update, &last_update, update_interval * 700 + rand() % 300); timeval_min(&tv, &update); if(selected_nexthop_metric < INFINITY) { int n = find_neighbour(selected_interface, &selected_nexthop, 0); assert(n >= 0); timeval_min(&tv, &neighbours[n].timeout); timeval_min(&tv, &selected_nexthop_timeout); } if(timeval_compare(&tv, &now) > 0) timeval_minus(&tv, &tv, &now); else tv = zerotv; FD_ZERO(&readfds); FD_SET(sock, &readfds); rc = select(sock + 1, &readfds, NULL, NULL, &tv); if(rc < 0 && errno != EINTR) { perror("select"); nap(1000); continue; } if(rc > 0) { /* Oh good, a packet. */ socklen_t sin6len = sizeof(sin6); rc = recvfrom(sock, buf, BUF_SIZE, 0, (struct sockaddr*)&sin6, &sin6len); if(rc < 0 || rc >= BUF_SIZE) { if(rc < 0 && errno != EAGAIN) { perror("recv"); nap(100); } continue; } if(sin6.sin6_family != PF_INET6) { fprintf(stderr, "Received unexpected packet in family %d.\n", sin6.sin6_family); nap(100); continue; } i = find_interface(sin6.sin6_scope_id); if(i < 0) { fprintf(stderr, "Received packet on unknown interface %d.\n", sin6.sin6_scope_id); nap(100); continue; } handle_packet(sock, buf, rc, &interfaces[i], &sin6.sin6_addr); } gettime(&now); if(selected_nexthop_metric < INFINITY) { int n = find_neighbour(selected_interface, &selected_nexthop, 0); assert(n >= 0); if(neighbour_expired(n, &now)) { /* Expire neighbour. */ flush_default_route(); delete_neighbour(n); } else if(timeval_compare(&now, &selected_nexthop_timeout) > 0) { /* Expire route. */ flush_default_route(); } /* Send a request? */ } /* Is it time to send hellos? */ if(timeval_minus_msec(&now, &last_hello) > hello_interval * 700) { for(i = 0; i < numinterfaces; i++) send_hello(sock, &interfaces[i]); last_hello = now; hello_count++; /* Make an expiry pass every ten hellos. */ if(hello_count >= 10) { expire_neighbours(); hello_count = 0; } } /* Is it time to send an update? */ if(timeval_minus_msec(&now, &last_update) > update_interval * 700) { for(i = 0; i < numinterfaces; i++) send_update(sock, &interfaces[i], 0); last_update = now; } } /* Send a bunch of retractions. */ for(i = 0; i < numinterfaces; i++) send_update(sock, &interfaces[i], 1); flush_default_route(); return 0; usage: fprintf(stderr, "Usage: sbabeld " "[-p prefix] [-u interval] [-h interval] [-c cost] interface...\n"); return 1; }