ntp_monitor.c revision 82498
154359Sroberto/* 254359Sroberto * ntp_monitor.c - monitor who is using the ntpd server 354359Sroberto */ 482498Sroberto 554359Sroberto#ifdef HAVE_CONFIG_H 682498Sroberto# include <config.h> 754359Sroberto#endif 854359Sroberto 954359Sroberto#include "ntpd.h" 1054359Sroberto#include "ntp_io.h" 1154359Sroberto#include "ntp_if.h" 1254359Sroberto#include "ntp_stdlib.h" 1354359Sroberto 1482498Sroberto#include <stdio.h> 1582498Sroberto#include <signal.h> 1682498Sroberto#ifdef HAVE_SYS_IOCTL_H 1782498Sroberto# include <sys/ioctl.h> 1882498Sroberto#endif 1982498Sroberto 2054359Sroberto/* 2154359Sroberto * I'm still not sure I like what I've done here. It certainly consumes 2254359Sroberto * memory like it is going out of style, and also may not be as low 2354359Sroberto * overhead as I'd imagined. 2454359Sroberto * 2554359Sroberto * Anyway, we record statistics based on source address, mode and version 2654359Sroberto * (for now, anyway. Check the code). The receive procedure calls us with 2754359Sroberto * the incoming rbufp before it does anything else. 2854359Sroberto * 2954359Sroberto * Each entry is doubly linked into two lists, a hash table and a 3054359Sroberto * most-recently-used list. When a packet arrives it is looked up 3154359Sroberto * in the hash table. If found, the statistics are updated and the 3254359Sroberto * entry relinked at the head of the MRU list. If not found, a new 3354359Sroberto * entry is allocated, initialized and linked into both the hash 3454359Sroberto * table and at the head of the MRU list. 3554359Sroberto * 3654359Sroberto * Memory is usually allocated by grabbing a big chunk of new memory 3754359Sroberto * and cutting it up into littler pieces. The exception to this when we 3854359Sroberto * hit the memory limit. Then we free memory by grabbing entries off 3954359Sroberto * the tail for the MRU list, unlinking from the hash table, and 4054359Sroberto * reinitializing. 4154359Sroberto * 4254359Sroberto * trimmed back memory consumption ... jdg 8/94 4354359Sroberto */ 4454359Sroberto 4554359Sroberto/* 4654359Sroberto * Limits on the number of structures allocated. This limit is picked 4754359Sroberto * with the illicit knowlege that we can only return somewhat less 4854359Sroberto * than 8K bytes in a mode 7 response packet, and that each structure 4954359Sroberto * will require about 20 bytes of space in the response. 5054359Sroberto * 5154359Sroberto * ... I don't believe the above is true anymore ... jdg 5254359Sroberto */ 5354359Sroberto#ifndef MAXMONMEM 5454359Sroberto#define MAXMONMEM 600 /* we allocate up to 600 structures */ 5554359Sroberto#endif 5654359Sroberto#ifndef MONMEMINC 5754359Sroberto#define MONMEMINC 40 /* allocate them 40 at a time */ 5854359Sroberto#endif 5954359Sroberto 6054359Sroberto/* 6154359Sroberto * Hashing stuff 6254359Sroberto */ 6354359Sroberto#define MON_HASH_SIZE 128 6454359Sroberto#define MON_HASH_MASK (MON_HASH_SIZE-1) 6554359Sroberto#define MON_HASH(addr) ((int)(ntohl((addr)) & MON_HASH_MASK)) 6654359Sroberto 6754359Sroberto/* 6854359Sroberto * Pointers to the hash table, the MRU list and the count table. Memory 6954359Sroberto * for the hash and count tables is only allocated if monitoring is turned on. 7054359Sroberto */ 7154359Srobertostatic struct mon_data *mon_hash[MON_HASH_SIZE]; /* array of list ptrs */ 7254359Srobertostruct mon_data mon_mru_list; 7354359Srobertostruct mon_data mon_fifo_list; 7454359Sroberto/* 7554359Sroberto * List of free structures structures, and counters of free and total 7654359Sroberto * structures. The free structures are linked with the hash_next field. 7754359Sroberto */ 7854359Srobertostatic struct mon_data *mon_free; /* the free list or null if none */ 7954359Sroberto 8054359Srobertostatic int mon_total_mem; /* total number of structures allocated */ 8154359Srobertostatic int mon_mem_increments; /* number of times we've called malloc() */ 8254359Sroberto 8354359Sroberto/* 8454359Sroberto * Initialization state. We may be monitoring, we may not. If 8554359Sroberto * we aren't, we may not even have allocated any memory yet. 8654359Sroberto */ 8754359Srobertoint mon_enabled; 8854359Srobertostatic int mon_have_memory; 8954359Sroberto 9054359Srobertostatic void mon_getmoremem P((void)); 9154359Srobertostatic void remove_from_hash P((struct mon_data *)); 9254359Sroberto 9354359Sroberto/* 9454359Sroberto * init_mon - initialize monitoring global data 9554359Sroberto */ 9654359Srobertovoid 9754359Srobertoinit_mon(void) 9854359Sroberto{ 9954359Sroberto /* 10054359Sroberto * Don't do much of anything here. We don't allocate memory 10154359Sroberto * until someone explicitly starts us. 10254359Sroberto */ 10354359Sroberto mon_enabled = MON_OFF; 10454359Sroberto mon_have_memory = 0; 10554359Sroberto 10654359Sroberto mon_total_mem = 0; 10754359Sroberto mon_mem_increments = 0; 10854359Sroberto mon_free = NULL; 10954359Sroberto memset((char *)&mon_hash[0], 0, sizeof mon_hash); 11054359Sroberto memset((char *)&mon_mru_list, 0, sizeof mon_mru_list); 11154359Sroberto memset((char *)&mon_fifo_list, 0, sizeof mon_fifo_list); 11254359Sroberto} 11354359Sroberto 11454359Sroberto 11554359Sroberto/* 11654359Sroberto * mon_start - start up the monitoring software 11754359Sroberto */ 11854359Srobertovoid 11954359Srobertomon_start( 12054359Sroberto int mode 12154359Sroberto ) 12254359Sroberto{ 12354359Sroberto 12454359Sroberto if (mon_enabled != MON_OFF) { 12554359Sroberto mon_enabled |= mode; 12654359Sroberto return; 12754359Sroberto } 12854359Sroberto if (mode == MON_OFF) 12954359Sroberto return; /* Ooops.. */ 13054359Sroberto 13154359Sroberto if (!mon_have_memory) { 13254359Sroberto mon_total_mem = 0; 13354359Sroberto mon_mem_increments = 0; 13454359Sroberto mon_free = NULL; 13554359Sroberto mon_getmoremem(); 13654359Sroberto mon_have_memory = 1; 13754359Sroberto } 13854359Sroberto 13954359Sroberto mon_mru_list.mru_next = &mon_mru_list; 14054359Sroberto mon_mru_list.mru_prev = &mon_mru_list; 14154359Sroberto 14254359Sroberto mon_fifo_list.fifo_next = &mon_fifo_list; 14354359Sroberto mon_fifo_list.fifo_prev = &mon_fifo_list; 14454359Sroberto 14554359Sroberto mon_enabled = mode; 14654359Sroberto} 14754359Sroberto 14854359Sroberto 14954359Sroberto/* 15054359Sroberto * mon_stop - stop the monitoring software 15154359Sroberto */ 15254359Srobertovoid 15354359Srobertomon_stop( 15454359Sroberto int mode 15554359Sroberto ) 15654359Sroberto{ 15754359Sroberto register struct mon_data *md, *md_next; 15854359Sroberto register int i; 15954359Sroberto 16054359Sroberto if (mon_enabled == MON_OFF) 16154359Sroberto return; 16254359Sroberto if ((mon_enabled & mode) == 0 || mode == MON_OFF) 16354359Sroberto return; 16454359Sroberto 16554359Sroberto mon_enabled &= ~mode; 16654359Sroberto if (mon_enabled != MON_OFF) 16754359Sroberto return; 16854359Sroberto 16954359Sroberto /* 17054359Sroberto * Put everything back on the free list 17154359Sroberto */ 17254359Sroberto for (i = 0; i < MON_HASH_SIZE; i++) { 17354359Sroberto md = mon_hash[i]; /* get next list */ 17454359Sroberto mon_hash[i] = NULL; /* zero the list head */ 17554359Sroberto while (md != NULL) { 17654359Sroberto md_next = md->hash_next; 17754359Sroberto md->hash_next = mon_free; 17854359Sroberto mon_free = md; 17954359Sroberto md = md_next; 18054359Sroberto } 18154359Sroberto } 18254359Sroberto 18354359Sroberto mon_mru_list.mru_next = &mon_mru_list; 18454359Sroberto mon_mru_list.mru_prev = &mon_mru_list; 18554359Sroberto 18654359Sroberto mon_fifo_list.fifo_next = &mon_fifo_list; 18754359Sroberto mon_fifo_list.fifo_prev = &mon_fifo_list; 18854359Sroberto} 18954359Sroberto 19054359Sroberto 19154359Sroberto/* 19254359Sroberto * ntp_monitor - record stats about this packet 19354359Sroberto */ 19454359Srobertovoid 19554359Srobertontp_monitor( 19654359Sroberto struct recvbuf *rbufp 19754359Sroberto ) 19854359Sroberto{ 19954359Sroberto register struct pkt *pkt; 20054359Sroberto register struct mon_data *md; 20154359Sroberto register u_long netnum; 20254359Sroberto register int hash; 20354359Sroberto register int mode; 20454359Sroberto 20554359Sroberto if (mon_enabled == MON_OFF) 20654359Sroberto return; 20754359Sroberto 20854359Sroberto pkt = &rbufp->recv_pkt; 20954359Sroberto netnum = NSRCADR(&rbufp->recv_srcadr); 21054359Sroberto hash = MON_HASH(netnum); 21154359Sroberto mode = PKT_MODE(pkt->li_vn_mode); 21254359Sroberto 21354359Sroberto md = mon_hash[hash]; 21454359Sroberto while (md != NULL) { 21554359Sroberto if (md->rmtadr == netnum && 21654359Sroberto /* ?? md->interface == rbufp->dstadr && ?? */ 21754359Sroberto md->mode == (u_char)mode) { 21854359Sroberto md->lasttime = current_time; 21954359Sroberto md->count++; 22054359Sroberto md->version = PKT_VERSION(pkt->li_vn_mode); 22154359Sroberto md->rmtport = NSRCPORT(&rbufp->recv_srcadr); 22254359Sroberto 22354359Sroberto /* 22454359Sroberto * Shuffle him to the head of the 22554359Sroberto * mru list. What a crock. 22654359Sroberto */ 22754359Sroberto md->mru_next->mru_prev = md->mru_prev; 22854359Sroberto md->mru_prev->mru_next = md->mru_next; 22954359Sroberto md->mru_next = mon_mru_list.mru_next; 23054359Sroberto md->mru_prev = &mon_mru_list; 23154359Sroberto mon_mru_list.mru_next->mru_prev = md; 23254359Sroberto mon_mru_list.mru_next = md; 23354359Sroberto 23454359Sroberto return; 23554359Sroberto } 23654359Sroberto md = md->hash_next; 23754359Sroberto } 23854359Sroberto 23954359Sroberto /* 24054359Sroberto * If we got here, this is the first we've heard of this 24154359Sroberto * guy. Get him some memory, either from the free list 24254359Sroberto * or from the tail of the MRU list. 24354359Sroberto */ 24454359Sroberto if (mon_free == NULL && mon_total_mem >= MAXMONMEM) { 24554359Sroberto /* 24654359Sroberto * Get it from MRU list 24754359Sroberto */ 24854359Sroberto md = mon_mru_list.mru_prev; 24954359Sroberto md->mru_prev->mru_next = &mon_mru_list; 25054359Sroberto mon_mru_list.mru_prev = md->mru_prev; 25154359Sroberto 25254359Sroberto remove_from_hash(md); 25354359Sroberto 25454359Sroberto /* 25554359Sroberto * Get it from FIFO list 25654359Sroberto */ 25754359Sroberto md->fifo_prev->fifo_next = md->fifo_next; 25854359Sroberto md->fifo_next->fifo_prev = md->fifo_prev; 25954359Sroberto 26054359Sroberto } else { 26154359Sroberto if (mon_free == NULL) /* if free list empty */ 26254359Sroberto mon_getmoremem(); /* then get more */ 26354359Sroberto md = mon_free; 26454359Sroberto mon_free = md->hash_next; 26554359Sroberto } 26654359Sroberto 26754359Sroberto /* 26854359Sroberto * Got one, initialize it 26954359Sroberto */ 27054359Sroberto md->lasttime = md->firsttime = current_time; 27154359Sroberto md->lastdrop = 0; 27254359Sroberto md->count = 1; 27354359Sroberto md->rmtadr = netnum; 27454359Sroberto md->rmtport = NSRCPORT(&rbufp->recv_srcadr); 27554359Sroberto md->mode = (u_char) mode; 27654359Sroberto md->version = PKT_VERSION(pkt->li_vn_mode); 27754359Sroberto md->interface = rbufp->dstadr; 27854359Sroberto md->cast_flags = ((rbufp->dstadr->flags & INT_MULTICAST) && 27954359Sroberto rbufp->fd == md->interface->fd) ? MDF_MCAST: rbufp->fd == 28054359Sroberto md->interface->bfd ? MDF_BCAST : MDF_UCAST; 28154359Sroberto 28254359Sroberto /* 28354359Sroberto * Drop him into front of the hash table. 28454359Sroberto * Also put him on top of the MRU list 28554359Sroberto * and at bottom of FIFO list 28654359Sroberto */ 28754359Sroberto 28854359Sroberto md->hash_next = mon_hash[hash]; 28954359Sroberto mon_hash[hash] = md; 29054359Sroberto 29154359Sroberto md->mru_next = mon_mru_list.mru_next; 29254359Sroberto md->mru_prev = &mon_mru_list; 29354359Sroberto mon_mru_list.mru_next->mru_prev = md; 29454359Sroberto mon_mru_list.mru_next = md; 29554359Sroberto 29654359Sroberto md->fifo_prev = mon_fifo_list.fifo_prev; 29754359Sroberto md->fifo_next = &mon_fifo_list; 29854359Sroberto mon_fifo_list.fifo_prev->fifo_next = md; 29954359Sroberto mon_fifo_list.fifo_prev = md; 30054359Sroberto} 30154359Sroberto 30254359Sroberto 30354359Sroberto/* 30454359Sroberto * mon_getmoremem - get more memory and put it on the free list 30554359Sroberto */ 30654359Srobertostatic void 30754359Srobertomon_getmoremem(void) 30854359Sroberto{ 30954359Sroberto register struct mon_data *md; 31054359Sroberto register int i; 31154359Sroberto struct mon_data *freedata; /* 'old' free list (null) */ 31254359Sroberto 31354359Sroberto md = (struct mon_data *)emalloc(MONMEMINC * sizeof(struct mon_data)); 31454359Sroberto freedata = mon_free; 31554359Sroberto mon_free = md; 31654359Sroberto 31754359Sroberto for (i = 0; i < (MONMEMINC-1); i++) { 31854359Sroberto md->hash_next = (md + 1); 31954359Sroberto md++; 32054359Sroberto } 32154359Sroberto 32254359Sroberto /* 32354359Sroberto * md now points at the last. Link in the rest of the chain. 32454359Sroberto */ 32554359Sroberto md->hash_next = freedata; 32654359Sroberto 32754359Sroberto mon_total_mem += MONMEMINC; 32854359Sroberto mon_mem_increments++; 32954359Sroberto} 33054359Sroberto 33154359Srobertostatic void 33254359Srobertoremove_from_hash( 33354359Sroberto struct mon_data *md 33454359Sroberto ) 33554359Sroberto{ 33654359Sroberto register int hash; 33754359Sroberto register struct mon_data *md_prev; 33854359Sroberto 33954359Sroberto hash = MON_HASH(md->rmtadr); 34054359Sroberto if (mon_hash[hash] == md) { 34154359Sroberto mon_hash[hash] = md->hash_next; 34254359Sroberto } else { 34354359Sroberto md_prev = mon_hash[hash]; 34454359Sroberto while (md_prev->hash_next != md) { 34554359Sroberto md_prev = md_prev->hash_next; 34654359Sroberto if (md_prev == NULL) { 34754359Sroberto /* logic error */ 34854359Sroberto return; 34954359Sroberto } 35054359Sroberto } 35154359Sroberto md_prev->hash_next = md->hash_next; 35254359Sroberto } 35354359Sroberto} 354