2 * ntp_monitor.c - monitor who is using the ntpd server
12 #include "ntp_stdlib.h"
16 #ifdef HAVE_SYS_IOCTL_H
17 # include <sys/ioctl.h>
21 * I'm still not sure I like what I've done here. It certainly consumes
22 * memory like it is going out of style, and also may not be as low
23 * overhead as I'd imagined.
25 * Anyway, we record statistics based on source address, mode and version
26 * (for now, anyway. Check the code). The receive procedure calls us with
27 * the incoming rbufp before it does anything else.
29 * Each entry is doubly linked into two lists, a hash table and a
30 * most-recently-used list. When a packet arrives it is looked up
31 * in the hash table. If found, the statistics are updated and the
32 * entry relinked at the head of the MRU list. If not found, a new
33 * entry is allocated, initialized and linked into both the hash
34 * table and at the head of the MRU list.
36 * Memory is usually allocated by grabbing a big chunk of new memory
37 * and cutting it up into littler pieces. The exception to this when we
38 * hit the memory limit. Then we free memory by grabbing entries off
39 * the tail for the MRU list, unlinking from the hash table, and
42 * trimmed back memory consumption ... jdg 8/94
46 * Limits on the number of structures allocated. This limit is picked
47 * with the illicit knowlege that we can only return somewhat less
48 * than 8K bytes in a mode 7 response packet, and that each structure
49 * will require about 20 bytes of space in the response.
51 * ... I don't believe the above is true anymore ... jdg
54 #define MAXMONMEM 600 /* we allocate up to 600 structures */
57 #define MONMEMINC 40 /* allocate them 40 at a time */
63 #define MON_HASH_SIZE 128
64 #define MON_HASH_MASK (MON_HASH_SIZE-1)
65 #define MON_HASH(addr) ((int)(ntohl((addr)) & MON_HASH_MASK))
68 * Pointers to the hash table, the MRU list and the count table. Memory
69 * for the hash and count tables is only allocated if monitoring is turned on.
71 static struct mon_data *mon_hash[MON_HASH_SIZE]; /* array of list ptrs */
72 struct mon_data mon_mru_list;
73 struct mon_data mon_fifo_list;
75 * List of free structures structures, and counters of free and total
76 * structures. The free structures are linked with the hash_next field.
78 static struct mon_data *mon_free; /* the free list or null if none */
80 static int mon_total_mem; /* total number of structures allocated */
81 static int mon_mem_increments; /* number of times we've called malloc() */
84 * Initialization state. We may be monitoring, we may not. If
85 * we aren't, we may not even have allocated any memory yet.
88 static int mon_have_memory;
90 static void mon_getmoremem P((void));
91 static void remove_from_hash P((struct mon_data *));
94 * init_mon - initialize monitoring global data
100 * Don't do much of anything here. We don't allocate memory
101 * until someone explicitly starts us.
103 mon_enabled = MON_OFF;
107 mon_mem_increments = 0;
109 memset((char *)&mon_hash[0], 0, sizeof mon_hash);
110 memset((char *)&mon_mru_list, 0, sizeof mon_mru_list);
111 memset((char *)&mon_fifo_list, 0, sizeof mon_fifo_list);
116 * mon_start - start up the monitoring software
124 if (mon_enabled != MON_OFF) {
129 return; /* Ooops.. */
131 if (!mon_have_memory) {
133 mon_mem_increments = 0;
139 mon_mru_list.mru_next = &mon_mru_list;
140 mon_mru_list.mru_prev = &mon_mru_list;
142 mon_fifo_list.fifo_next = &mon_fifo_list;
143 mon_fifo_list.fifo_prev = &mon_fifo_list;
150 * mon_stop - stop the monitoring software
157 register struct mon_data *md, *md_next;
160 if (mon_enabled == MON_OFF)
162 if ((mon_enabled & mode) == 0 || mode == MON_OFF)
165 mon_enabled &= ~mode;
166 if (mon_enabled != MON_OFF)
170 * Put everything back on the free list
172 for (i = 0; i < MON_HASH_SIZE; i++) {
173 md = mon_hash[i]; /* get next list */
174 mon_hash[i] = NULL; /* zero the list head */
176 md_next = md->hash_next;
177 md->hash_next = mon_free;
183 mon_mru_list.mru_next = &mon_mru_list;
184 mon_mru_list.mru_prev = &mon_mru_list;
186 mon_fifo_list.fifo_next = &mon_fifo_list;
187 mon_fifo_list.fifo_prev = &mon_fifo_list;
192 * ntp_monitor - record stats about this packet
196 struct recvbuf *rbufp
199 register struct pkt *pkt;
200 register struct mon_data *md;
201 register u_long netnum;
205 if (mon_enabled == MON_OFF)
208 pkt = &rbufp->recv_pkt;
209 netnum = NSRCADR(&rbufp->recv_srcadr);
210 hash = MON_HASH(netnum);
211 mode = PKT_MODE(pkt->li_vn_mode);
215 if (md->rmtadr == netnum &&
216 /* ?? md->interface == rbufp->dstadr && ?? */
217 md->mode == (u_char)mode) {
218 md->lasttime = current_time;
220 md->version = PKT_VERSION(pkt->li_vn_mode);
221 md->rmtport = NSRCPORT(&rbufp->recv_srcadr);
224 * Shuffle him to the head of the
225 * mru list. What a crock.
227 md->mru_next->mru_prev = md->mru_prev;
228 md->mru_prev->mru_next = md->mru_next;
229 md->mru_next = mon_mru_list.mru_next;
230 md->mru_prev = &mon_mru_list;
231 mon_mru_list.mru_next->mru_prev = md;
232 mon_mru_list.mru_next = md;
240 * If we got here, this is the first we've heard of this
241 * guy. Get him some memory, either from the free list
242 * or from the tail of the MRU list.
244 if (mon_free == NULL && mon_total_mem >= MAXMONMEM) {
246 * Get it from MRU list
248 md = mon_mru_list.mru_prev;
249 md->mru_prev->mru_next = &mon_mru_list;
250 mon_mru_list.mru_prev = md->mru_prev;
252 remove_from_hash(md);
255 * Get it from FIFO list
257 md->fifo_prev->fifo_next = md->fifo_next;
258 md->fifo_next->fifo_prev = md->fifo_prev;
261 if (mon_free == NULL) /* if free list empty */
262 mon_getmoremem(); /* then get more */
264 mon_free = md->hash_next;
268 * Got one, initialize it
270 md->lasttime = md->firsttime = current_time;
274 md->rmtport = NSRCPORT(&rbufp->recv_srcadr);
275 md->mode = (u_char) mode;
276 md->version = PKT_VERSION(pkt->li_vn_mode);
277 md->interface = rbufp->dstadr;
278 md->cast_flags = ((rbufp->dstadr->flags & INT_MULTICAST) &&
279 rbufp->fd == md->interface->fd) ? MDF_MCAST: rbufp->fd ==
280 md->interface->bfd ? MDF_BCAST : MDF_UCAST;
283 * Drop him into front of the hash table.
284 * Also put him on top of the MRU list
285 * and at bottom of FIFO list
288 md->hash_next = mon_hash[hash];
291 md->mru_next = mon_mru_list.mru_next;
292 md->mru_prev = &mon_mru_list;
293 mon_mru_list.mru_next->mru_prev = md;
294 mon_mru_list.mru_next = md;
296 md->fifo_prev = mon_fifo_list.fifo_prev;
297 md->fifo_next = &mon_fifo_list;
298 mon_fifo_list.fifo_prev->fifo_next = md;
299 mon_fifo_list.fifo_prev = md;
304 * mon_getmoremem - get more memory and put it on the free list
309 register struct mon_data *md;
311 struct mon_data *freedata; /* 'old' free list (null) */
313 md = (struct mon_data *)emalloc(MONMEMINC * sizeof(struct mon_data));
317 for (i = 0; i < (MONMEMINC-1); i++) {
318 md->hash_next = (md + 1);
323 * md now points at the last. Link in the rest of the chain.
325 md->hash_next = freedata;
327 mon_total_mem += MONMEMINC;
328 mon_mem_increments++;
337 register struct mon_data *md_prev;
339 hash = MON_HASH(md->rmtadr);
340 if (mon_hash[hash] == md) {
341 mon_hash[hash] = md->hash_next;
343 md_prev = mon_hash[hash];
344 while (md_prev->hash_next != md) {
345 md_prev = md_prev->hash_next;
346 if (md_prev == NULL) {
351 md_prev->hash_next = md->hash_next;