/* * Allocate a default DCE and a hash table for per-IP address DCEs */ void dce_stack_init(ip_stack_t *ipst) { int i; ipst->ips_dce_default = kmem_cache_alloc(dce_cache, KM_SLEEP); bzero(ipst->ips_dce_default, sizeof (dce_t)); ipst->ips_dce_default->dce_flags = DCEF_DEFAULT; ipst->ips_dce_default->dce_generation = DCE_GENERATION_INITIAL; ipst->ips_dce_default->dce_last_change_time = TICK_TO_SEC(ddi_get_lbolt64()); ipst->ips_dce_default->dce_refcnt = 1; /* Should never go away */ ipst->ips_dce_default->dce_ipst = ipst; /* This must be a power of two since we are using IRE_ADDR_HASH macro */ ipst->ips_dce_hashsize = 256; ipst->ips_dce_hash_v4 = kmem_zalloc(ipst->ips_dce_hashsize * sizeof (dcb_t), KM_SLEEP); ipst->ips_dce_hash_v6 = kmem_zalloc(ipst->ips_dce_hashsize * sizeof (dcb_t), KM_SLEEP); for (i = 0; i < ipst->ips_dce_hashsize; i++) { rw_init(&ipst->ips_dce_hash_v4[i].dcb_lock, NULL, RW_DEFAULT, NULL); rw_init(&ipst->ips_dce_hash_v6[i].dcb_lock, NULL, RW_DEFAULT, NULL); } }
int getrusage(int who, struct rusage * rusage) { #ifdef WIN32 if (rusage) memset(rusage, 0, sizeof(rusage)); #else struct tms tms; int tick_rate = CLK_TCK; /* ticks per second */ clock_t u, s; if (rusage == (struct rusage *) NULL) { errno = EFAULT; return -1; } if (times(&tms) < 0) { /* errno set by times */ return -1; } switch (who) { case RUSAGE_SELF: u = tms.tms_utime; s = tms.tms_stime; break; case RUSAGE_CHILDREN: u = tms.tms_cutime; s = tms.tms_cstime; break; default: errno = EINVAL; return -1; } #define TICK_TO_SEC(T, RATE) ((T)/(RATE)) #define TICK_TO_USEC(T,RATE) (((T)%(RATE)*1000000)/RATE) rusage->ru_utime.tv_sec = TICK_TO_SEC(u, tick_rate); rusage->ru_utime.tv_usec = TICK_TO_USEC(u, tick_rate); rusage->ru_stime.tv_sec = TICK_TO_SEC(s, tick_rate); rusage->ru_stime.tv_usec = TICK_TO_USEC(u, tick_rate); #endif return 0; }
/* * Atomically looks for a non-default DCE, and if not found tries to create one. * If there is no memory it returns NULL. * When an entry is created we increase the generation number on * the default DCE so that conn_ip_output will detect there is a new DCE. * ifindex should only be used with link-local addresses. */ dce_t * dce_lookup_and_add_v6(const in6_addr_t *dst, uint_t ifindex, ip_stack_t *ipst) { uint_t hash; dcb_t *dcb; dce_t *dce; /* We should not create entries for link-locals w/o an ifindex */ ASSERT(!(IN6_IS_ADDR_LINKSCOPE(dst)) || ifindex != 0); hash = IRE_ADDR_HASH_V6(*dst, ipst->ips_dce_hashsize); dcb = &ipst->ips_dce_hash_v6[hash]; rw_enter(&dcb->dcb_lock, RW_WRITER); for (dce = dcb->dcb_dce; dce != NULL; dce = dce->dce_next) { if (IN6_ARE_ADDR_EQUAL(&dce->dce_v6addr, dst) && dce->dce_ifindex == ifindex) { mutex_enter(&dce->dce_lock); if (!DCE_IS_CONDEMNED(dce)) { dce_refhold(dce); mutex_exit(&dce->dce_lock); rw_exit(&dcb->dcb_lock); return (dce); } mutex_exit(&dce->dce_lock); } } dce = kmem_cache_alloc(dce_cache, KM_NOSLEEP); if (dce == NULL) { rw_exit(&dcb->dcb_lock); return (NULL); } bzero(dce, sizeof (dce_t)); dce->dce_ipst = ipst; /* No netstack_hold */ dce->dce_v6addr = *dst; dce->dce_ifindex = ifindex; dce->dce_generation = DCE_GENERATION_INITIAL; dce->dce_ipversion = IPV6_VERSION; dce->dce_last_change_time = TICK_TO_SEC(ddi_get_lbolt64()); dce_refhold(dce); /* For the hash list */ /* Link into list */ if (dcb->dcb_dce != NULL) dcb->dcb_dce->dce_ptpn = &dce->dce_next; dce->dce_next = dcb->dcb_dce; dce->dce_ptpn = &dcb->dcb_dce; dcb->dcb_dce = dce; dce->dce_bucket = dcb; atomic_add_32(&dcb->dcb_cnt, 1); dce_refhold(dce); /* For the caller */ rw_exit(&dcb->dcb_lock); /* Initialize dce_ident to be different than for the last packet */ dce->dce_ident = ipst->ips_dce_default->dce_ident + 1; dce_increment_generation(ipst->ips_dce_default); return (dce); }
/* * Atomically looks for a non-default DCE, and if not found tries to create one. * If there is no memory it returns NULL. * When an entry is created we increase the generation number on * the default DCE so that conn_ip_output will detect there is a new DCE. */ dce_t * dce_lookup_and_add_v4(ipaddr_t dst, ip_stack_t *ipst) { uint_t hash; dcb_t *dcb; dce_t *dce; hash = IRE_ADDR_HASH(dst, ipst->ips_dce_hashsize); dcb = &ipst->ips_dce_hash_v4[hash]; rw_enter(&dcb->dcb_lock, RW_WRITER); for (dce = dcb->dcb_dce; dce != NULL; dce = dce->dce_next) { if (dce->dce_v4addr == dst) { mutex_enter(&dce->dce_lock); if (!DCE_IS_CONDEMNED(dce)) { dce_refhold(dce); mutex_exit(&dce->dce_lock); rw_exit(&dcb->dcb_lock); return (dce); } mutex_exit(&dce->dce_lock); } } dce = kmem_cache_alloc(dce_cache, KM_NOSLEEP); if (dce == NULL) { rw_exit(&dcb->dcb_lock); return (NULL); } bzero(dce, sizeof (dce_t)); dce->dce_ipst = ipst; /* No netstack_hold */ dce->dce_v4addr = dst; dce->dce_generation = DCE_GENERATION_INITIAL; dce->dce_ipversion = IPV4_VERSION; dce->dce_last_change_time = TICK_TO_SEC(ddi_get_lbolt64()); dce_refhold(dce); /* For the hash list */ /* Link into list */ if (dcb->dcb_dce != NULL) dcb->dcb_dce->dce_ptpn = &dce->dce_next; dce->dce_next = dcb->dcb_dce; dce->dce_ptpn = &dcb->dcb_dce; dcb->dcb_dce = dce; dce->dce_bucket = dcb; dce_refhold(dce); /* For the caller */ rw_exit(&dcb->dcb_lock); /* Initialize dce_ident to be different than for the last packet */ dce->dce_ident = ipst->ips_dce_default->dce_ident + 1; dce_increment_generation(ipst->ips_dce_default); return (dce); }
static void* flush_thread_main(void *in) { hlld_config *config; hlld_setmgr *mgr; int *should_run; UNPACK_ARGS(); // Perform the initial checkpoint with the manager setmgr_client_checkpoint(mgr); syslog(LOG_INFO, "Flush thread started. Interval: %d seconds.", config->flush_interval); unsigned int ticks = 0; while (*should_run) { usleep(PERIODIC_TIME_USEC); setmgr_client_checkpoint(mgr); if ((TICK_TO_SEC(++ticks) % config->flush_interval) == 0 && *should_run) { // Time how long this takes struct timeval start, end; gettimeofday(&start, NULL); // List all the sets syslog(LOG_INFO, "Scheduled flush started."); hlld_set_list_head *head; int res = setmgr_list_sets(mgr, NULL, &head); if (res != 0) { syslog(LOG_WARNING, "Failed to list sets for flushing!"); continue; } // Flush all, ignore errors since // sets might get deleted in the process hlld_set_list *node = head->head; unsigned int cmds = 0; while (node) { setmgr_flush_set(mgr, node->set_name); if (!(++cmds % PERIODIC_CHECKPOINT)) setmgr_client_checkpoint(mgr); node = node->next; } // Compute the elapsed time gettimeofday(&end, NULL); syslog(LOG_INFO, "Flushed %d sets in %d msecs", head->size, timediff_msec(&start, &end)); // Cleanup setmgr_cleanup_list(head); } } return NULL; }
static void* unmap_thread_main(void *in) { hlld_config *config; hlld_setmgr *mgr; int *should_run; UNPACK_ARGS(); // Perform the initial checkpoint with the manager setmgr_client_checkpoint(mgr); syslog(LOG_INFO, "Cold unmap thread started. Interval: %d seconds.", config->cold_interval); unsigned int ticks = 0; while (*should_run) { usleep(PERIODIC_TIME_USEC); setmgr_client_checkpoint(mgr); if ((TICK_TO_SEC(++ticks) % config->cold_interval) == 0 && *should_run) { // Time how long this takes struct timeval start, end; gettimeofday(&start, NULL); // List the cold sets syslog(LOG_INFO, "Cold unmap started."); hlld_set_list_head *head; int res = setmgr_list_cold_sets(mgr, &head); if (res != 0) { continue; } // Close the sets, save memory hlld_set_list *node = head->head; unsigned int cmds = 0; while (node) { syslog(LOG_DEBUG, "Unmapping set '%s' for being cold.", node->set_name); setmgr_unmap_set(mgr, node->set_name); if (!(++cmds % PERIODIC_CHECKPOINT)) setmgr_client_checkpoint(mgr); node = node->next; } // Compute the elapsed time gettimeofday(&end, NULL); syslog(LOG_INFO, "Unmapped %d sets in %d msecs", head->size, timediff_msec(&start, &end)); // Cleanup setmgr_cleanup_list(head); } } return NULL; }
/* * Reclaim a fraction of dce's in the dcb. * For now we have a higher probability to delete DCEs without DCE_PMTU. */ static void dcb_reclaim(dcb_t *dcb, ip_stack_t *ipst, uint_t fraction) { uint_t fraction_pmtu = fraction*4; uint_t hash; dce_t *dce, *nextdce; rw_enter(&dcb->dcb_lock, RW_WRITER); for (dce = dcb->dcb_dce; dce != NULL; dce = nextdce) { nextdce = dce->dce_next; /* Clear DCEF_PMTU if the pmtu is too old */ mutex_enter(&dce->dce_lock); if ((dce->dce_flags & DCEF_PMTU) && TICK_TO_SEC(ddi_get_lbolt64()) - dce->dce_last_change_time > ipst->ips_ip_pathmtu_interval) { dce->dce_flags &= ~DCEF_PMTU; mutex_exit(&dce->dce_lock); dce_increment_generation(dce); } else { mutex_exit(&dce->dce_lock); } hash = RANDOM_HASH((uint64_t)(uintptr_t)dce); if (dce->dce_flags & DCEF_PMTU) { if (hash % fraction_pmtu != 0) continue; } else { if (hash % fraction != 0) continue; } IP_STAT(ipst, ip_dce_reclaim_deleted); dce_delete_locked(dcb, dce); dce_refrele(dce); } rw_exit(&dcb->dcb_lock); }
/* This code works on: * univel * solaris_i386 * sco * solaris_sparc * svr4 * hpux 9.* * win32 * which currently is all the supported platforms that don't have a * native version of getrusage(). So, if configure decides to compile * this file at all, we just use this version unconditionally. */ int getrusage(int who, struct rusage * rusage) { #ifdef __WIN32__ FILETIME starttime; FILETIME exittime; FILETIME kerneltime; FILETIME usertime; ULARGE_INTEGER li; if (who != RUSAGE_SELF) { /* Only RUSAGE_SELF is supported in this implementation for now */ errno = EINVAL; return -1; } if (rusage == (struct rusage *) NULL) { errno = EFAULT; return -1; } memset(rusage, 0, sizeof(struct rusage)); if (GetProcessTimes(GetCurrentProcess(), &starttime, &exittime, &kerneltime, &usertime) == 0) { _dosmaperr(GetLastError()); return -1; } /* Convert FILETIMEs (0.1 us) to struct timeval */ memcpy(&li, &kerneltime, sizeof(FILETIME)); li.QuadPart /= 10L; /* Convert to microseconds */ rusage->ru_stime.tv_sec = li.QuadPart / 1000000L; rusage->ru_stime.tv_usec = li.QuadPart % 1000000L; memcpy(&li, &usertime, sizeof(FILETIME)); li.QuadPart /= 10L; /* Convert to microseconds */ rusage->ru_utime.tv_sec = li.QuadPart / 1000000L; rusage->ru_utime.tv_usec = li.QuadPart % 1000000L; #else /* all but __WIN32__ */ struct tms tms; int tick_rate = CLK_TCK; /* ticks per second */ clock_t u, s; if (rusage == (struct rusage *) NULL) { errno = EFAULT; return -1; } if (times(&tms) < 0) { /* errno set by times */ return -1; } switch (who) { case RUSAGE_SELF: u = tms.tms_utime; s = tms.tms_stime; break; case RUSAGE_CHILDREN: u = tms.tms_cutime; s = tms.tms_cstime; break; default: errno = EINVAL; return -1; } #define TICK_TO_SEC(T, RATE) ((T)/(RATE)) #define TICK_TO_USEC(T,RATE) (((T)%(RATE)*1000000)/RATE) rusage->ru_utime.tv_sec = TICK_TO_SEC(u, tick_rate); rusage->ru_utime.tv_usec = TICK_TO_USEC(u, tick_rate); rusage->ru_stime.tv_sec = TICK_TO_SEC(s, tick_rate); rusage->ru_stime.tv_usec = TICK_TO_USEC(u, tick_rate); #endif /* __WIN32__ */ return 0; }
/* * Get current zone maximum burst time. */ rctl_qty_t cpucaps_zone_get_burst_time(zone_t *zone) { return (zone->zone_cpucap != NULL ? (rctl_qty_t)(TICK_TO_SEC(zone->zone_cpucap->cap_burst_limit)) : 0); }