Annotation of embedaddon/bird/nest/neighbor.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>