Annotation of embedaddon/bird/nest/neighbor.c, revision 1.1.1.2
1.1 misho 1: /*
2: * BIRD -- Neighbor Cache
3: *
4: * (c) 1998--2000 Martin Mares <mj@ucw.cz>
5: *
6: * Can be freely distributed and used under the terms of the GNU GPL.
7: */
8:
9: /**
10: * DOC: Neighbor cache
11: *
12: * Most routing protocols need to associate their internal state data with
13: * neighboring routers, check whether an address given as the next hop
14: * attribute of a route is really an address of a directly connected host
15: * and which interface is it connected through. Also, they often need to
16: * be notified when a neighbor ceases to exist or when their long awaited
17: * neighbor becomes connected. The neighbor cache is there to solve all
18: * these problems.
19: *
20: * The neighbor cache maintains a collection of neighbor entries. Each
21: * entry represents one IP address corresponding to either our directly
22: * connected neighbor or our own end of the link (when the scope of the
23: * address is set to %SCOPE_HOST) together with per-neighbor data belonging to a
24: * single protocol.
25: *
26: * Active entries represent known neighbors and are stored in a hash
27: * table (to allow fast retrieval based on the IP address of the node) and
28: * two linked lists: one global and one per-interface (allowing quick
29: * processing of interface change events). Inactive entries exist only
30: * when the protocol has explicitly requested it via the %NEF_STICKY
31: * flag because it wishes to be notified when the node will again become
32: * a neighbor. Such entries are enqueued in a special list which is walked
1.1.1.2 ! misho 33: * whenever an interface changes its state to up. Neighbor entry VRF
! 34: * association is implied by respective protocol.
1.1 misho 35: *
36: * When a neighbor event occurs (a neighbor gets disconnected or a sticky
37: * inactive neighbor becomes connected), the protocol hook neigh_notify()
38: * is called to advertise the change.
39: */
40:
41: #undef LOCAL_DEBUG
42:
43: #include "nest/bird.h"
44: #include "nest/iface.h"
45: #include "nest/protocol.h"
46: #include "lib/resource.h"
47:
48: #define NEIGH_HASH_SIZE 256
49:
50: static slab *neigh_slab;
51: static list sticky_neigh_list, neigh_hash_table[NEIGH_HASH_SIZE];
52:
53: static inline uint
54: neigh_hash(struct proto *p, ip_addr *a)
55: {
56: return (p->hash_key ^ ipa_hash(*a)) & (NEIGH_HASH_SIZE-1);
57: }
58:
59: static int
60: if_connected(ip_addr *a, struct iface *i, struct ifa **ap)
61: {
62: struct ifa *b;
63:
64: if (!(i->flags & IF_UP))
65: {
66: *ap = NULL;
67: return -1;
68: }
69:
70: WALK_LIST(b, i->addrs)
71: {
72: *ap = b;
73:
74: if (ipa_equal(*a, b->ip))
75: return SCOPE_HOST;
76: if (b->flags & IA_PEER)
77: {
78: if (ipa_equal(*a, b->opposite))
79: return b->scope;
80: }
81: else
82: {
83: if (ipa_in_net(*a, b->prefix, b->pxlen))
84: {
85: #ifndef IPV6
86: if ((b->pxlen < (BITS_PER_IP_ADDRESS - 1)) &&
87: (ipa_equal(*a, b->prefix) || /* Network address */
88: ipa_equal(*a, b->brd))) /* Broadcast */
89: {
90: *ap = NULL;
91: return -1;
92: }
93: #endif
94:
95: return b->scope;
96: }
97: }
98: }
99:
100: *ap = NULL;
101: return -1;
102: }
103:
104: /**
105: * neigh_find - find or create a neighbor entry.
106: * @p: protocol which asks for the entry.
107: * @a: pointer to IP address of the node to be searched for.
108: * @flags: 0 or %NEF_STICKY if you want to create a sticky entry.
109: *
110: * Search the neighbor cache for a node with given IP address. If
111: * it's found, a pointer to the neighbor entry is returned. If no
112: * such entry exists and the node is directly connected on
113: * one of our active interfaces, a new entry is created and returned
114: * to the caller with protocol-dependent fields initialized to zero.
115: * If the node is not connected directly or *@a is not a valid unicast
116: * IP address, neigh_find() returns %NULL.
117: */
118: neighbor *
119: neigh_find(struct proto *p, ip_addr *a, unsigned flags)
120: {
121: return neigh_find2(p, a, NULL, flags);
122: }
123:
124:
125: neighbor *
126: neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags)
127: {
128: neighbor *n;
129: int class, scope = -1;
130: uint h = neigh_hash(p, a);
131: struct iface *i;
132: struct ifa *addr;
133:
134: WALK_LIST(n, neigh_hash_table[h]) /* Search the cache */
135: if (n->proto == p && ipa_equal(*a, n->addr) && (!ifa || (ifa == n->iface)))
136: return n;
137:
138: class = ipa_classify(*a);
139: if (class < 0) /* Invalid address */
140: return NULL;
141: if (((class & IADDR_SCOPE_MASK) == SCOPE_HOST) ||
142: (((class & IADDR_SCOPE_MASK) == SCOPE_LINK) && (ifa == NULL)) ||
143: !(class & IADDR_HOST))
144: return NULL; /* Bad scope or a somecast */
145:
146: if (ifa)
147: {
148: scope = if_connected(a, ifa, &addr);
149: flags |= NEF_BIND;
150:
151: if ((scope < 0) && (flags & NEF_ONLINK))
152: scope = class & IADDR_SCOPE_MASK;
153: }
154: else
155: WALK_LIST(i, iface_list)
1.1.1.2 ! misho 156: if ((!p->vrf_set || p->vrf == i->master) &&
! 157: ((scope = if_connected(a, i, &addr)) >= 0))
! 158: {
1.1 misho 159: ifa = i;
160: break;
161: }
162:
163: /* scope < 0 means i don't know neighbor */
164: /* scope >= 0 implies ifa != NULL */
165:
166: if ((scope < 0) && !(flags & NEF_STICKY))
167: return NULL;
168:
169: n = sl_alloc(neigh_slab);
170: n->addr = *a;
171: if (scope >= 0)
172: {
173: add_tail(&neigh_hash_table[h], &n->n);
174: add_tail(&ifa->neighbors, &n->if_n);
175: }
176: else
177: {
178: add_tail(&sticky_neigh_list, &n->n);
179: scope = -1;
180: }
181: n->iface = ifa;
182: n->ifa = addr;
183: n->proto = p;
184: n->data = NULL;
185: n->aux = 0;
186: n->flags = flags;
187: n->scope = scope;
188: return n;
189: }
190:
191: /**
192: * neigh_dump - dump specified neighbor entry.
193: * @n: the entry to dump
194: *
195: * This functions dumps the contents of a given neighbor entry
196: * to debug output.
197: */
198: void
199: neigh_dump(neighbor *n)
200: {
201: debug("%p %I ", n, n->addr);
202: if (n->iface)
203: debug("%s ", n->iface->name);
204: else
205: debug("[] ");
206: debug("%s %p %08x scope %s", n->proto->name, n->data, n->aux, ip_scope_text(n->scope));
207: if (n->flags & NEF_STICKY)
208: debug(" STICKY");
209: debug("\n");
210: }
211:
212: /**
213: * neigh_dump_all - dump all neighbor entries.
214: *
215: * This function dumps the contents of the neighbor cache to
216: * debug output.
217: */
218: void
219: neigh_dump_all(void)
220: {
221: neighbor *n;
222: int i;
223:
224: debug("Known neighbors:\n");
225: WALK_LIST(n, sticky_neigh_list)
226: neigh_dump(n);
227: for(i=0; i<NEIGH_HASH_SIZE; i++)
228: WALK_LIST(n, neigh_hash_table[i])
229: neigh_dump(n);
230: debug("\n");
231: }
232:
233: static void
234: neigh_up(neighbor *n, struct iface *i, int scope, struct ifa *a)
235: {
236: n->iface = i;
237: n->ifa = a;
238: n->scope = scope;
239: add_tail(&i->neighbors, &n->if_n);
240: rem_node(&n->n);
241: add_tail(&neigh_hash_table[neigh_hash(n->proto, &n->addr)], &n->n);
242: DBG("Waking up sticky neighbor %I\n", n->addr);
243: if (n->proto->neigh_notify && n->proto->core_state != FS_FLUSHING)
244: n->proto->neigh_notify(n);
245: }
246:
247: static void
248: neigh_down(neighbor *n)
249: {
250: DBG("Flushing neighbor %I on %s\n", n->addr, n->iface->name);
251: rem_node(&n->if_n);
252: if (! (n->flags & NEF_BIND))
253: n->iface = NULL;
254: n->ifa = NULL;
255: n->scope = -1;
256: if (n->proto->neigh_notify && n->proto->core_state != FS_FLUSHING)
257: n->proto->neigh_notify(n);
258: rem_node(&n->n);
259: if (n->flags & NEF_STICKY)
260: {
261: add_tail(&sticky_neigh_list, &n->n);
262:
263: /* Respawn neighbor if there is another matching prefix */
264: struct iface *i;
265: struct ifa *a;
266: int scope;
267:
268: if (!n->iface)
269: WALK_LIST(i, iface_list)
270: if ((scope = if_connected(&n->addr, i, &a)) >= 0)
271: {
272: neigh_up(n, i, scope, a);
273: return;
274: }
275: }
276: else
277: sl_free(neigh_slab, n);
278: }
279:
280:
281: /**
282: * neigh_if_up: notify neighbor cache about interface up event
283: * @i: interface in question
284: *
285: * Tell the neighbor cache that a new interface became up.
286: *
287: * The neighbor cache wakes up all inactive sticky neighbors with
288: * addresses belonging to prefixes of the interface @i.
289: */
290: void
291: neigh_if_up(struct iface *i)
292: {
293: struct ifa *a;
294: neighbor *n, *next;
295: int scope;
296:
297: WALK_LIST_DELSAFE(n, next, sticky_neigh_list)
298: if ((!n->iface || n->iface == i) &&
299: ((scope = if_connected(&n->addr, i, &a)) >= 0))
300: neigh_up(n, i, scope, a);
301: }
302:
303: /**
304: * neigh_if_down - notify neighbor cache about interface down event
305: * @i: the interface in question
306: *
307: * Notify the neighbor cache that an interface has ceased to exist.
308: *
309: * It causes all entries belonging to neighbors connected to this interface
310: * to be flushed.
311: */
312: void
313: neigh_if_down(struct iface *i)
314: {
315: node *x, *y;
316:
317: WALK_LIST_DELSAFE(x, y, i->neighbors)
318: neigh_down(SKIP_BACK(neighbor, if_n, x));
319: }
320:
321: /**
322: * neigh_if_link - notify neighbor cache about interface link change
323: * @i: the interface in question
324: *
325: * Notify the neighbor cache that an interface changed link state.
326: * All owners of neighbor entries connected to this interface are
327: * notified.
328: */
329: void
330: neigh_if_link(struct iface *i)
331: {
332: node *x, *y;
333:
334: WALK_LIST_DELSAFE(x, y, i->neighbors)
335: {
336: neighbor *n = SKIP_BACK(neighbor, if_n, x);
337: if (n->proto->neigh_notify && n->proto->core_state != FS_FLUSHING)
338: n->proto->neigh_notify(n);
339: }
340: }
341:
342: /**
343: * neigh_ifa_update: notify neighbor cache about interface address add or remove event
344: * @a: interface address in question
345: *
346: * Tell the neighbor cache that an address was added or removed.
347: *
348: * The neighbor cache wakes up all inactive sticky neighbors with
349: * addresses belonging to prefixes of the interface belonging to @ifa
350: * and causes all unreachable neighbors to be flushed.
351: */
352: void
353: neigh_ifa_update(struct ifa *a)
354: {
355: struct iface *i = a->iface;
356: node *x, *y;
357:
358: /* Remove all neighbors whose scope has changed */
359: WALK_LIST_DELSAFE(x, y, i->neighbors)
360: {
361: struct ifa *aa;
362: neighbor *n = SKIP_BACK(neighbor, if_n, x);
363: if (if_connected(&n->addr, i, &aa) != n->scope)
364: neigh_down(n);
365: }
366:
367: /* Wake up all sticky neighbors that are reachable now */
368: neigh_if_up(i);
369: }
370:
371: static inline void
372: neigh_prune_one(neighbor *n)
373: {
374: if (n->proto->proto_state != PS_DOWN)
375: return;
376: rem_node(&n->n);
377: if (n->scope >= 0)
378: rem_node(&n->if_n);
379: sl_free(neigh_slab, n);
380: }
381:
382: /**
383: * neigh_prune - prune neighbor cache
384: *
385: * neigh_prune() examines all neighbor entries cached and removes those
386: * corresponding to inactive protocols. It's called whenever a protocol
387: * is shut down to get rid of all its heritage.
388: */
389: void
390: neigh_prune(void)
391: {
392: neighbor *n;
393: node *m;
394: int i;
395:
396: DBG("Pruning neighbors\n");
397: for(i=0; i<NEIGH_HASH_SIZE; i++)
398: WALK_LIST_DELSAFE(n, m, neigh_hash_table[i])
399: neigh_prune_one(n);
400: WALK_LIST_DELSAFE(n, m, sticky_neigh_list)
401: neigh_prune_one(n);
402: }
403:
404: /**
405: * neigh_init - initialize the neighbor cache.
406: * @if_pool: resource pool to be used for neighbor entries.
407: *
408: * This function is called during BIRD startup to initialize
409: * the neighbor cache module.
410: */
411: void
412: neigh_init(pool *if_pool)
413: {
414: int i;
415:
416: neigh_slab = sl_new(if_pool, sizeof(neighbor));
417: init_list(&sticky_neigh_list);
418: for(i=0; i<NEIGH_HASH_SIZE; i++)
419: init_list(&neigh_hash_table[i]);
420: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>