Annotation of embedaddon/bird/nest/neighbor.c, revision 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>