21
* I'm still not sure I like what I've done here. It certainly consumes
20
* I'm still not sure I like what I've done here. It certainly consumes
22
21
* memory like it is going out of style, and also may not be as low
23
22
* 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.
24
* Anyway, we record statistics based on source address, mode and
25
* version (for now, anyway. Check the code). The receive procedure
26
* calls us with the incoming rbufp before it does anything else.
29
28
* 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.
29
* most-recently-used list. When a packet arrives it is looked up in
30
* the hash table. If found, the statistics are updated and the entry
31
* relinked at the head of the MRU list. If not found, a new entry is
32
* allocated, initialized and linked into both the hash table and at the
33
* 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
35
* Memory is usually allocated by grabbing a big chunk of new memory and
36
* cutting it up into littler pieces. The exception to this when we hit
37
* the memory limit. Then we free memory by grabbing entries off the
38
* tail for the MRU list, unlinking from the hash table, and
42
41
* trimmed back memory consumption ... jdg 8/94
46
44
* Limits on the number of structures allocated. This limit is picked
47
45
* with the illicit knowlege that we can only return somewhat less
63
61
#define MON_HASH_SIZE 128
64
62
#define MON_HASH_MASK (MON_HASH_SIZE-1)
65
#define MON_HASH(addr) ((int)(ntohl((addr)) & MON_HASH_MASK))
63
#define MON_HASH(addr) sock_hash(addr)
68
66
* 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.
67
* for the hash and count tables is only allocated if monitoring is
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;
70
static struct mon_data *mon_hash[MON_HASH_SIZE]; /* list ptrs */
71
struct mon_data mon_mru_list;
75
74
* List of free structures structures, and counters of free and total
76
75
* 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() */
77
static struct mon_data *mon_free; /* free list or null if none */
78
static int mon_total_mem; /* total structures allocated */
79
static int mon_mem_increments; /* times called malloc() */
84
82
* Initialization state. We may be monitoring, we may not. If
85
83
* we aren't, we may not even have allocated any memory yet.
85
int mon_enabled; /* enable switch */
86
u_long mon_age = 3000; /* preemption limit */
88
87
static int mon_have_memory;
90
88
static void mon_getmoremem P((void));
91
89
static void remove_from_hash P((struct mon_data *));
106
104
mon_total_mem = 0;
107
105
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);
107
memset(&mon_hash[0], 0, sizeof mon_hash);
108
memset(&mon_mru_list, 0, sizeof mon_mru_list);
199
189
register struct pkt *pkt;
200
190
register struct mon_data *md;
201
register u_long netnum;
191
struct sockaddr_storage addr;
202
192
register int hash;
203
193
register int mode;
205
195
if (mon_enabled == MON_OFF)
208
198
pkt = &rbufp->recv_pkt;
209
netnum = NSRCADR(&rbufp->recv_srcadr);
210
hash = MON_HASH(netnum);
199
memset(&addr, 0, sizeof(addr));
200
memcpy(&addr, &(rbufp->recv_srcadr), sizeof(addr));
201
hash = MON_HASH(&addr);
211
202
mode = PKT_MODE(pkt->li_vn_mode);
213
203
md = mon_hash[hash];
214
204
while (md != NULL) {
215
if (md->rmtadr == netnum &&
216
/* ?? md->interface == rbufp->dstadr && ?? */
217
md->mode == (u_char)mode) {
207
* Match address only to conserve MRU size.
209
if (SOCKCMP(&md->rmtadr, &addr)) {
210
md->drop_count = current_time - md->lasttime;
218
211
md->lasttime = current_time;
213
md->rmtport = NSRCPORT(&rbufp->recv_srcadr);
214
md->mode = (u_char) mode;
220
215
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.
218
* Shuffle to the head of the MRU list.
227
220
md->mru_next->mru_prev = md->mru_prev;
228
221
md->mru_prev->mru_next = md->mru_next;
242
234
* or from the tail of the MRU list.
244
236
if (mon_free == NULL && mon_total_mem >= MAXMONMEM) {
246
* Get it from MRU list
239
* Preempt from the MRU list if old enough.
248
241
md = mon_mru_list.mru_prev;
242
if (((u_long)RANDOM & 0xffffffff) / FRAC >
243
(double)(current_time - md->lasttime) / mon_age)
249
246
md->mru_prev->mru_next = &mon_mru_list;
250
247
mon_mru_list.mru_prev = md->mru_prev;
252
248
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 */
250
if (mon_free == NULL)
264
253
mon_free = md->hash_next;
268
257
* Got one, initialize it
270
md->lasttime = md->firsttime = current_time;
259
md->avg_interval = 0;
260
md->lasttime = current_time;
263
memset(&md->rmtadr, 0, sizeof(md->rmtadr));
264
memcpy(&md->rmtadr, &addr, sizeof(addr));
274
265
md->rmtport = NSRCPORT(&rbufp->recv_srcadr);
275
266
md->mode = (u_char) mode;
276
267
md->version = PKT_VERSION(pkt->li_vn_mode);
277
268
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;
269
md->cast_flags = (u_char)(((rbufp->dstadr->flags & INT_MULTICAST) &&
270
rbufp->fd == md->interface->fd) ? MDF_MCAST: rbufp->fd ==
271
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
274
* Drop him into front of the hash table. Also put him on top of
288
277
md->hash_next = mon_hash[hash];
289
278
mon_hash[hash] = md;
291
279
md->mru_next = mon_mru_list.mru_next;
292
280
md->mru_prev = &mon_mru_list;
293
281
mon_mru_list.mru_next->mru_prev = md;
294
282
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;
311
294
struct mon_data *freedata; /* 'old' free list (null) */
313
md = (struct mon_data *)emalloc(MONMEMINC * sizeof(struct mon_data));
296
md = (struct mon_data *)emalloc(MONMEMINC *
297
sizeof(struct mon_data));
314
298
freedata = mon_free;
317
300
for (i = 0; i < (MONMEMINC-1); i++) {
318
301
md->hash_next = (md + 1);